아래는 Basic Authentication을 피해야 하는 이유입니다.
기밀성 부족
무결성 부족
인증 강도 부족
multi-factor authentication 지원 불가
표준 인증 메커니즘에는 아래와 같은 것들이 있습니다.
OAuth
OpenID
SAML
Password hashing algorithms
Two-factor authentication(2FA)
Max Retry
최대 로그인 시도 가능 횟수를 설정하는 것입니다.
이 로그인 시도 수를 넘어 로그인에 실패했을 경우 해당 유저의 계정을 일정 시간 차단합니다.
이는 로그인 공격을 하는 것을 막아줍니다.
Jail
IP주소를 차단하거나 너무 많은 로그인에 실패한 유저 계정을 차단하는 것입니다.
이것 또한 공격을 막아줍니다.
JWT Secret 좋은 걸로 만들기
강한 Secret key는 무작위의 길고 복잡한 형태를 가집니다.
또한 안전한 곳에 보관되어야 하며 주기적으로 바꿔주는 것이 좋습니다.
JWT 헤더에서 알고리즘 추출하지 말고 백엔드에서 사용하기
JWT는 공격자에 의해 만들어져 보내질 수 있습니다.
이때 JWT의 헤더의 알고리즘을 이용하여 JWT를 해독한다면 공격자의 JWT에 대해서는 JWT공격자가 설정한 알고리즘으로 JWT를 해독하게 되어 위험합니다.
그렇기 때문에 서버에서 따로 특정 알고리즘으로 JWT를 해독하게 하는 것이 좋습니다.
JWT 만료 기간 설정하기
JWT의 만료기간은 합리적이면서 짧은 시간을 설정하는 것이 보안에 중요합니다.
여기서 합리적이라는 말은 유저의 사용성에 대해서도 고려해야 한다는 것입니다.
JWT에 민감한 정보 넣지 말기
JWT의 내용은 쉽게 알아낼 수 있으므로 민감한 정보를 JWT에 담아 보내는 짓은 하지 말아야 합니다.
JWT의 사이즈를 줄이기 위해 페이로드 작게 만들기
작은 페이로드는 네트워크 오버헤드를 줄여줍니다. 이는 인증 처리 속도를 향상시키며 공격자가 시스템 과부하를 목표로 하는 공격의 위험을 줄입니다.
요청 횟수 제한하기
DDOS와 같은 공격은 매우 많은 요청을 보내 서버를 마비시킵니다.
이러한 공격을 예방하기 위해 요청 횟수를 제한하는 것이 중요합니다.
HTTPS 사용하기
서버가 HTTP대신에 HTTPS를 사용하게 해야 합니다.
HSTS 헤더 사용하기
SSL/TLS와 함께 HSTS헤더 사용해야 합니다.
SSL Strip는 공격자가 클라이언트와 서버 사이의 트래픽에 개입하여 HTTPS로 연결되어야 하는 것을 HTTP로 연결되게 만드는 공격입니다.
이렇게 되면 메세지가 평문으로 주고 받게 되어 보안에 매우 취약해집니다.
HSTS헤더는 보안 헤더인데 브라우저가 해당 사이트를 HTTPS를 통해서만 접근할 수 있게 강제합니다. 이는 SSL Strip 공격을 막습니다.
디렉토리 목록 기능 끄기
웹 서버의 디렉토리 목록 기능은 사용자가 서버의 특정 폴더 내용을 볼 수 있게 하는 기능입니다.
기본적으로 웹 서버는 디렉터리 목록이 활성화되어 있어 서버에 접근 권한이 있는 사용자라면 해당 폴더의 모든 파일과 폴더 목록을 볼 수 있습니다.
디렉터리 목록을 비활성화하는 것이 중요한데 공격자가 서버의 민감한 파일과 디렉토리에 접근하는 것을 방지하기 위해서입니다.
Private API 접근 제한하기
Private API에 대한 접근은 허용된 IP에 대해서만 이루어지게 해야합니다.
이렇게 함으로써 권한이 없는 접근을 막을 수 있습니다.
redirect_uri를 언제나 서버에서 검증하자
redirect_uri는 인증이 완료될 시 리다이렉트할 주소를 가지는 파라미터입니다.
redirect_uri는 OAuth에서 인증 이후 authorization code나 access token을 클라이언트한테 주기 위해 사용됩니다.
Open redirect attack은 redirect_uri를 변경함으로써 사용자를 악의적인 웹사이트로 이동시키는데 이때 authorization code나 access token이 탈취당할 위험이 있습니다.
그렇기 때문에 redirect_uri를 검증하는 것이 중요합니다.
'response_type=token'형식을 피하고 코드로 주자.
'response_type=token'은 OAuth에서 redirect_uri에 직접 access token을 삽입해 access token을 받는 방식입니다.
이 방식은 implicit grant flow라고도 불립니다.
이는 access token에 대한 기록이 브라우저 히스토리나 서버 로그에 남기 때문에 보안상 취약합니다.
authorization code grant flow 방식을 사용하길 권장합니다.
'state'파라미터를 이용하여 CSRF attack 막기
CSRF attack란 악의적인 웹사이트가 최근에 인증받은 유저의 정보를 이용해 서버에 요청을 보내는 공격입니다.
이를 막기 위해 'state'파라미터를 사용하면 되는데 'state' 파라미터는 클라이언트의 애플리케이션에서 생성된 고유한 값을 저장하기 위해 사용됩니다.
이 'state' 파라미터 값은 인증 서버에서 검증되고 리다이렉트 됩니다.
default scope를 사용하고 각각의 애플리케이션의 scope를 검증하자.
OAuth에서 scope는 클라이언트 애플리케이션의 권한 허용범위와 접근 레벨을 특정하기 위해 사용됩니다.
default scope를 가지고 각각의 애플리케이션에 대해 scope를 검증하는 것은 같은 보안 기준을 가지고 접근 통제를 하게 만들어 줍니다.
적절한 HTTP 메서드를 사용하자
각 메서드들은 다음과 같습니다. GET (read), POST (create), PUT/PATCH (replace/update), and DELETE (to delete a record) 이를 잘 지키는 것이 중요합니다. 만약 적절한 메서드가 아니라면 405 Method Not Allowed로 응답합시다.
Content-type 헤더를 검증하자.
Content-type 헤더를 검증함으로써 API를 더 안전하게 만들 수 있습니다.
유저의 Input 데이터를 검증하자.
악의적인 사용자가 Input 데이터를 통해 서버를 공격할 수 있습니다. 그렇기 때문에 Input 데이터를 검증하고 해당 입력이 서버를 공격하지 못하게 하는 것이 중요합니다.
Authorization 헤더를 이용해서 토큰을 보내자.
쿼리나 바디를 통해 토큰을 보내는 것은 로그에 기록되거나 캐쉬되기 때문에 권장되지 않습니다. 또한 CSRF공격에도 취약해 집니다.
그렇기 때문에 Authorization 헤더를 통해 토큰을 보내는 것을 권장합니다.
서버에서만 암호화를 하자
클라이언트(웹브라우저)에서 암호화를 하는 것은 리버스 엔지니어링이 쉬우므로 서버에서만 암호화 하는 것이 좋습니다.
API 게이트웨이를 사용하자.
API 게이트웨이는 중앙 집중형 방식으로 운영되어 관리와 보안에 있어서 이점을 제공해줍니다.
아래는 API 게이트웨이가 API 보안을 향상시키는 방법입니다.
인증과 인가
사용자의 인증과 인가를 API 게이트웨이가 다루면서 개별 API에 대한 부담을 줄이고 앱들의 전체적인 일관성을 향상시킵니다.
트래픽 필터와 제한
API 게이트웨이는 트래피 필터와 제한이 가능합니다. 이를 통해 DDOS나 Brute For Attack나 다른 종류의 공격을 막을 수 있습니다.
암호화와 복호화
API 게이트웨이는 민감한 정보에 대한 암호화와 복호화를 처리하여 데이터를 보호할 수 있습니다.
로그 기록과 모니터링
API 게이트웨이는 API 트래픽에 대한 모니터링과 로그 기록을 남길 수 있기 때문에 보안을 위협하는 이슈나 다른 이슈에 대응하게 해줍니다.
보안 도구들을 통한 통합
API 게이트웨이는 WAF나 SIEM이나 다른 보안 도구들을 통해 추가적인 보안 레이어를 만들 수 있습니다.
'X-Content-Type-options: nosniff' 헤더를 보내자.
MIME type sniffing attakcs을 막기 위해서는 'X-Content-Type-options: nosniff' 헤더를 사용해야 합니다.
MIME type sniffing attakcs이란 웹 브라우저가 웹 서버로부터 전달받은 콘텐츠의 MIME타입을 잘못 판발하여 발생하는 보안 취약점을 악용한 공격입니다.
'X-Content-Type-options: nosniff'헤더는 브라우저가 예상한 타입이 아니더라도 응답 컨텐츠 타입을 무시하지 못하게 합니다.
일부 부라우저는 헤더가 아닌 파일안의 내용을 통해 컨텐츠 타입을 추정하는데 이는 XSS공격에 취약하게 만듭니다.
'X-Frame-Options: Deny' 헤더를 보내자.
'X-Frame-Options: Deny' 옵션은 iframe이 보여지는 것을 막습니다.
이는 Clickjacking attack를 막기위해 사용됩니다.
'Content-Security-Policy: default-src 'none'' 헤더를 보내자.
XSS공격을 막는데 매우 좋은 방법입니다.
이 헤더는 다른 외부의 리소스를 허용하지 않게 만들어 보안을 강화합니다.
만약 외부 리소스를 허용해야한다면 CSP정책을 수정해 특정 리소스만 허용하면 됩니다.
Fingerprints 헤더를 사용하지 말자.(예시: x-powered-by 등)
Fingerprints 헤더란 웹 서버나 웹 서버의 버전을 파악하게 해주는 헤더를 말합니다.
이러한 정보를 공격자가 취약점을 더 쉽게 찾게 만들어주기 때문에 헤더에 포함시키지 않아야 합니다.
Content-Type 헤더를 강제하자.
Content-Type 헤더를 강제함으로써 클라이언트와 서버가 상호간에 허용한 형식으로 데이터가 통신되게 만듦으로써 보안에 도움을 줍니다.
민감한 정보를 반환하는 것을 피하자.
필요한 정보만을 반환하게 만듦으로써 사용자의 민감한 정보가 유출되지 않게 해야합니다.
응답에 상태코드를 적절히 사용하자.
적절한 응답 상태코드를 보내는 것이 중요합니다.
이는 크라이언트가 그들의 요청에 대한 결과를 이해하고 적절히 대처할 수 있게 만들어 주기 때문입니다.
모든 엔드포인트에 대해 인증을 통해 제대로 보호되고 있는지 확인하자.
인증 프로세스에서 발생할 수 있는 문제점을 미리 식별하고 해결함으로써 API가 Brute Force 공격, Credential stuffing, session hijacking 등과 같은 공격을 방지할 수 있게 합니다.
URL에 개인적인 ID를 포함하지 말자.
/user/654321/orders와 같이 유저의 ID가 들어가 있는 형식을 사용하지말고 /me/orders 같이 유저 ID가 없는 형식의 URL을 사용하자.
데이터베이스에 UUID를 사용하자.
1씩 상승하는 ID를 사용하는 것보다 UUID를 사용하는 것이 보안면에서 더 좋습니다.
UUID는 고유한 값으로 랜덤한 값이 생성되지만 1씩 증가하는 ID는 랜덤하지 않기 때문에 보안에 취약합니다.
XXE 공격을 막기 위해 엔티티 파싱을 비활성화하라.
XXE공격은 XML입력 값을 신뢰하지 못하는 소스로부터 파싱할 때 생기는 공격입니다.
XXE 공격을 막지 않으면 XXE를 통해 SSRF공격을 할 수 있습니다. 이 뿐만 아니라 민감한 정보의 유출, 서비스 거부 공격 같은 다른 공격에도 취약해집니다.
엔티티 확장을 비활성화하라.
엔티티 확장을 비활성화함으로써 XXE공격이나 YAML tag injection 공격을 막을 수 있습니다.
파일 업로드에 CDN을 이용하자.
CDN을 이용하는것은 API서버에 대한 DDOS공격을 줄여준다.
HTTP Blocking을 피하자.
너무 많은 요청이나 방대한 양의 자료를 처리해야할 때 HTTP Blocking 현상이 일어납니다.
이는 애플리케이션이 응답하지 못하거나 서버가 충돌하는 결과를 낳기도 합니다.
그렇기 때문에 이러한 작업을 백그라운드 작업으로 돌리거나 비동기 작업으로 돌려야 합니다.
이를 위해 메세지 큐같은 것을 이용할 수 있습니다.
production 환경에서는 debug모드를 끄자.
debug모드는 디버그할때 쓰는 모드입니다. 실제 배포되었을 때 사용되서는 안됩니다. 민감한 정보들을 보여줄 수 있기 때문입니다.
non-executalbe stacks을 쓰자.
콜 스택이나 실행 스택은 자료구조로써 컴퓨터 프로그램이 관리하고 함수의 호출 순서와 지역 변수 그리고 다른 데이터를 추적하기 위해 사용합니다.
non-executalbe stack은 보안 메커니즘으로 스택이 실행가능한 코드가 실행되는 것을 막아줍니다.
(C나 C++ 같은 저수준 언어에서 신경써야 하는 내용입니다.)
모든 요청과 응답과 에러를 모니터링 하자.
모든 요청, 응답, 오류를 모니터링하기 위해 에이전트를 사용하는 것은 실시간 모니터링과 비정상 활동 또는 잠재적 공격의 감지를 가능하게 합니다. 에이전트는 응답 시간, 오류율, 사용 패턴과 같은 메트릭을 추적하도록 구성할 수 있으며, 이는 공격을 나타낼 수 있는 이상 현상을 식별하는 데 도움이 됩니다.
모든 요청과 응답을 모니터링함으로써 에이전트는 API의 동작에 대한 가시성을 제공하여 잠재적 보안 취약점이나 약점을 식별할 수 있습니다.
또한 에이전트는 API를 통해 흐르는 모든 데이터를 기록하고 분석하는 데 사용할 수 있어 디버깅 및 감사 목적으로 유용합니다.
알람을 설정하자
SMS, Slack, Email, Kibana, Cloudwatch같은 알람 서비스를 이용하면 이슈나 시스템의 비정상적인 작동에 빠르게 대처할 수 있습니다.
민감한 정보를 로그 기록하는 것을 피하자.
비밀번호나 신용 카드 번호나 개인 정보를 로그에 기록하는 것을 피해야 합니다.
로그 기록은 외부에 노출될 수 있기 때문입니다.
침입 탐지 시스템(IDS)이나 침입 방지 시스템(IPS)을 사용하자.
IDS와 IPS는 공격을 탐지하고 방어하는데 도움을 줍니다.
위 시스템은 들어오는 모든 트래픽과 나가는 모든 트래픽을 모니터링하며 이상한 현상을 탐지했을 때 해당 트래픽을 차단해줍니다.
Network Intrusion Detection System, Host-based Intrusion Detection System, Network Intrusion Prevention System 같은 도구를 통해 구현가능합니다.
단위 및 통합 테스트를 통해 설계와 구현을 검토하자.
단위 테스트와 통합 테스트는 API 코드와 설계에서 취약점을 식별하는 데 도움이 될 수 있습니다.
예를 들어, 입력 검증 오류, 인증 및 권한 부여 결함, 기타 보안 관련 문제 등을 찾아낼 수 있습니다.
포괄적인 테스트를 수행함으로써 개발자는 API가 의도한 대로 작동하고 SQL 인젝션, 크로스 사이트 스크립팅(XSS) 등과 같은 일반적인 공격에 대해 안전하다는 것을 보장할 수 있습니다.
충분한 테스트는 또한 성능 병목 현상을 식별하고 해결하며, 확장성과 신뢰성을 향상시키고 API의 전반적인 품질을 보장하는 데 도움이 됩니다.
코드 리뷰를 하자. 그리고 스스로 코드를 승인하는 행위를 하지 말자.
좋은 코드 리뷰 프로세스를 가지는 것은 잠재적인 보안 이슈와 취약점을 찾게 도와줍니다.
또한 코드에 대해 코드를 작성한 사람이 해당 코드를 승인하지 못하게 함으로써 잠재적인 실수를 잡을 수 있습니다.
지속적으로 보안 분석을 하자.
지속적인 보안 분석은 코드 기반 보안 취약점을 알아내는데 도움을 줍니다.
의존성들을 확인하고 최신 상태를 유지하자.
써드 파티 라이브러리나 컴포넌트들은 보안 위협에 노출될 수 있습니다.
이러한 위협은 오래되거나 안전하지 않은 의존성으로 생기는 일입니다.
정기적으로 취약점을 파악하고 의존성을 최신 상태로 유지함으로써 보안을 강화할 수 있습니다.
롤백 솔루션을 만들어 두자.
새로운 버전의 출시는 예상 외의 버그나 이슈를 가질 수 있습니다. 그렇기 때문에 이전 버전으로 돌아갈 수 있는 롤백 솔루션을 가지고 있는 것이 중요합니다.