구체적인 문의 내용
회사에서 개발 업무를 담당하고 있습니다. 기존에 운영하던 서비스에 OAuth 인증 기능을 추가하려고 합니다.
설계나 구현할 때 보안 상 고려해야 하는 사항은 무엇이 있나요?
보안 고려사항
1. 통신구간 암호화를 사용한다.
– 통신상의 도청, 변조 공격을 방지하기 위하여 Client와 OAuth server간의 모든 통신구간을 HTTP/TLS로 암호화를 적용한다.(TLS1.2이상)
– MiTMA(main in the middle attack)을 방지하기 위해서는 OAuth Server의 인증서를 Client에서 검증할 수 있도록 E2E암호화를 적용한다.
2. 안전하게 Client Secrets(Client ID에 대한 비밀키)을 저장한다.
– Client secrets는 client측에 안전하게 저장되어야 하며 평문으로 전송되거나 코드내에 포함되어 있어서는 안된다.
– 비인가접근으로 부터 client secrets를 보호하기 위하여 암호화 또는 안전한 키관리를 사용한다.
3. 안전한 Token storage를 사용한다.
– 비인가접근으로 부터 token을 보호하기 위하여 client측에 암호화 등으로 안전하게 저장되어야 한다.
– 안전한 저장 메커니즘으로써 암호화된 로컬 저장 또는 Secure HTTP-only cookies를 고려한다.
4. state parameter를 구현한다.
– state parameter는 CSRF공격을 방지하기 위하여 OAuth 인증요청에서 사용되어야 한다.
– state parameter는 CSRF 공격을 방지하기 위해 redirect response에서 변경되지 않은상태로 리턴되고 client 측에서 검증되어야 한다.
5. 적절한 인증절차를 구현한다.
– 인가자만 접근하도록 적합한 사용자 인증, 동의 절차 등을 포함한 인증 절차를 구현한다.
– 사용자가 적절하게 인증되고 권한부여되었는지 확인하는 절차를 구현한다.
6. Token을 검증한다.
– token은 Server측에서 signature 확인과 만료여부 확인 등을 검증해야 한다.
– token은 비인가자의 접근을 방지하기 위하여 인증성에 대하여 검증되어야 한다.
7. 접근허용 범위를 제한한다.
– toaken의 허용범위를 요청된 범위로만 접근을 제한하도록 한다.
– 사용자 데이터에 대한 무단 접근을 초래할 수 있는 광범위하거나 무제한적인 접근 허용 범위를 부여하지 않는다.
8. 모니터링 및 기록관리
– 사용자 데이터에 대한 접근을 추적하고 감사하기 위해 모니터링 및 로깅기능을 구현한다.
– 모든 OAuth권한 요청과 접근을 모니터링하고 로그기록을 남긴다.
9. 적절한 Error handling을 한다.
– 정보노출과 무단접근을 방지하기 위하여 적절한 Error Handling을 구현한다.
– Error 메시지에서 client secrets과 같은 중요정보가 노출되지 않도록 한다.
10. 정기적 검토 및 업데이트
– 신규 보안위협과 취약점을 해결하기 위하여 정기적으로 검토하고 업데이트한다.
– OAuth보안 관련 최신 모범사례를 가지고 필요한 변경사항을 구현하고 최신상태로 유지한다.
Flask 프레임워크를 이용한 OAuth 인증 Python 예제 코드
flask 프레임 워크로 OAuth 2.0을 구현한 Python 예제 코드
from flask import Flask, redirect, request
import requests
app = Flask(__name__)
client_id = "YOUR_CLIENT_ID"
client_secret = "YOUR_CLIENT_SECRET"
redirect_uri = "YOUR_REDIRECT_URI"
auth_uri = "https://oauth.example.com/authorize"
token_uri = "https://oauth.example.com/token"
@app.route("/")
def index():
return redirect(f"{auth_uri}?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code")
@app.route("/callback")
def callback():
code = request.args.get("code")
if code:
data = {
"grant_type": "authorization_code",
"code": code,
"redirect_uri": redirect_uri,
"client_id": client_id,
"client_secret": client_secret
}
try:
response = requests.post(token_uri, data=data)
response.raise_for_status()
except requests.exceptions.HTTPError as e:
return "Error while obtaining access token: " + str(e)
access_token = response.json().get("access_token")
if access_token:
# access token을 안전하게 저장, 사용
return "Access token obtained successfully."
return "Failed to obtain access token."
if __name__ == "__main__":
app.run(debug=True)
