결론
쿠키에는 여전히 몇 가지 취약점이 있지만 가능한 한 쿠키에 비해 선호 localStorage됩니다. 왜요?
•
localStorage와 쿠키는 모두 XSS 공격에 취약하지만 httpOnly 쿠키를 사용하는 경우 공격자가 공격하기가 더 어렵습니다.
•
•
Authorization: Bearer 헤더 를 사용해야 하거나 JWT가 4KB보다 큰 경우 에도 여전히 작동하도록 할 수 있습니다 . 이는 OWASP 커뮤니티의 권장 사항과도 일치합니다.
JavaScript에서 항상 데이터에 액세스할 수 있으므로 세션 식별자를 로컬 저장소에 저장하지 마십시오. 쿠키는 httpOnly플래그를 사용하여 이러한 위험을 완화할 수 있습니다 .
+ (MDN)
Secure 쿠키는 HTTPS 프로토콜 상에서 암호화된(encrypted ) 요청일 경우에만 전송됩니다. 하지만 Secure일지라도 민감한 정보는 절대 쿠키에 저장되면 안됩니다, 본질적으로 안전하지 않고 이 플래그가 당신에게 실질적인 보안(real protection)를 제공하지 않기 때문입니다. 크롬52 혹은 파이어폭스52로 시작한다면, 안전하지 않은 사이트(http:) 는 쿠키에 Secure 설정을 지시할 수 없습니다.
Cross-site 스크립팅 (XSS (en-US)) 공격을 방지하기 위해, HttpOnly쿠키는 JavaScript의 Document.cookie API에 접근할 수 없습니다; 그들은 서버에게 전송되기만 합니다. 예를 들어, 서버 쪽에서 지속되고 있는 세션의 쿠키는 JavaScript를 사용할 필요성이 없기 때문에 HttpOnly플래그가 설정될 것입니다.
그렇다면 쿠키를 사용하여 OAuth 2.0 토큰을 유지하려면 어떻게 해야 합니까?
요약하자면, 토큰을 저장할 수 있는 다양한 방법은 다음과 같습니다.
•
옵션 1:localStorage
액세스 토큰
을 XSS에 취약한 위치 에 저장합니다 .
•
옵션 2:httpOnly
액세스 토큰을
쿠키 에 저장: CSRF에 취약하지만 완화할 수 있습니다. XSS에 대한 노출 측면에서 조금 더 낫습니다.
•
옵션 3:httpOnly옵션 3
쿠키에 새로 고침 토큰 저장: CSRF로부터 안전하고 XSS에 대한 노출 측면에서 조금 더 좋습니다. 3가지 옵션 중 가장 좋은
이 어떻게 작동 하는지 살펴보겠습니다 .
액세스 토큰을 메모리에 저장하고 새로 고침 토큰을 쿠키에 저장
이것이 CSRF로부터 안전한 이유는 무엇입니까?
양식 제출 /refresh_token이 작동하고 새 액세스 토큰이 반환되지만 공격자가 HTML 양식을 사용하는 경우 응답을 읽을 수 없습니다. 공격자 가 응답 을 성공적으로 작성 fetch하거나 AJAX요청하고 읽는 것을 방지하려면 인증 서버의 CORS 정책이 인증되지 않은 웹 사이트의 요청을 방지하도록 올바르게 설정되어야 합니다.
이 설정은 어떻게 작동합니까?
1단계: 사용자가 인증되면 Access Token과 Refresh Token을 반환합니다.
사용자가 인증된 후 인증 서버는 access_token및 를 반환합니다 refresh_token. 는 access_token응답 본문에 포함되며이 refresh_token쿠키에 포함됩니다.
새로 고침 토큰 쿠키 설정:
◦
httpOnly
JavaScript가 읽지 못하도록 플래그를 사용합니다 .
◦
secure=true
HTTPS를 통해서만 보낼 수 있도록 플래그를 사용합니다 .
◦
SameSite=strict
CSRF를 방지하기 위해 가능 하면 플래그를 사용하십시오 . Authorization Server에 프런트 엔드와 동일한 사이트가 있는 경우에만 사용할 수 있습니다. 그렇지 않은 경우 권한 부여 서버는 백엔드에서 CORS 헤더를 설정하거나 다른 방법을 사용하여 승인된 웹 사이트에서만 새로 고침 토큰 요청을 수행할 수 있도록 해야 합니다.
2단계: 액세스 토큰을 메모리에 저장
토큰을 메모리에 저장한다는 것은 이 액세스 토큰을 프런트 엔드 사이트의 변수에 넣는 것을 의미합니다. 예, 이는 사용자가 탭을 전환하거나 사이트를 새로 고치면 액세스 토큰이 사라짐을 의미합니다. 이것이 바로 새로 고침 토큰이 있는 이유입니다.
3단계: 갱신 토큰을 사용하여 액세스 토큰 갱신
액세스 토큰이 없거나 만료된 경우 /refresh_token엔드포인트에 도달하면 1단계에서 쿠키에 저장된 새로 고침 토큰이 요청에 포함됩니다. 새 액세스 토큰을 얻은 다음 이를 API 요청에 사용할 수 있습니다.
즉, JWT 토큰이 4KB보다 클 수 있으며 Authorization 헤더에 넣을 수도 있습니다.
그게 다야!
You can use JWT localstorage and prevent CSRF attacks. When you are using a token bearer you are saying to the server that you only allow request with this token from the current browser client, so if a hacker stole the token, he can't make the request because the token are not coming from the original client. JWT is secure and for more security just config the life time of the token less than 8 hours.
JWT 로컬 저장소를 사용하여 CSRF 공격을 방지할 수 있습니다. 토큰 보유자를 사용할 때 서버에 현재 브라우저 클라이언트의 이 토큰으로만 요청을 허용하므로 해커가 토큰을 훔쳐갔을 경우 원래 클라이언트에서 토큰이 전송되지 않아 요청을 할 수 없다고 서버에 말합니다. JWT는 안전하며 보안을 강화하기 위해 토큰의 수명을 8시간 미만으로 구성하기만 하면 됩니다.
안녕 Michelle, 기사 고마워.
localStorage의 가능한 콘을 하나 더 언급하고 싶습니다. SSR 앱을 생성하면 local스토리지를 토큰 저장에 사용할 수 없게 됩니다.
민감한 정보를 로컬 스토리지에 저장하는 것은 트위터나 인스타그램에 해당 정보를 게시하는 것과 같습니다.
Local storage wasn’t designed to be used as a secure storage mechanism in a browser. It was designed to be a simple string only key/value store that developers could use to build slightly more complex single-page apps.
— Randall Degges
When you store sensitive information in local storage, you’re essentially using the most dangerous thing in the world(javascript) to store your most sensitive information in the worst vault ever created.
— Randall Degges
주요 문제는 사이트 간 스크립팅 공격(XSS)에 자신을 노출시킨다는 것입니다.
요약하자면 공격자가 웹 사이트에서 JS를 실행할 수 있는 권한을 얻은 경우 추가 권한 없이 로컬 스토리지에 액세스할 수 있으며 저장된 모든 정보를 자신의 도메인과 같은 원하는 위치로 보낼 수 있습니다.
다시 말해, 사용자의 데이터와 같은 로컬 스토리지에 있는 중요한 모든 것이 손상될 수 있습니다.
당신의 웹사이트에 다음과 같은 스크립트 태그가 내장되어 있다고 가정해보자.
<script src="https://favouritejslibrary.com/minified.js"><script>
유감스럽게도 favouritejslibrary.com이 악의적인 당사자에 의해 손상되어 minified.js 스크립트가 다음과 같이 수정되는 경우:
로컬 스토리지의 모든 데이터를 루프 방식으로 살펴봅니다.
도난당한 정보를 수집하기 위해 만들어진 API로 보냅니다.
그러니, 두 가지를 기억하라:
인터넷에 보이는 모든 라이브러리를 사용하지 마십시오.
로컬 스토리지에 조금이라도 중요한 항목을 저장하지 마십시오.
이 내용을 알고 나면 타사 라이브러리 사용을 완전히 피하는 것을 고려할 수 있지만, 웹 사이트를 구축하는 데 몇 년이 걸리는 경우를 제외하고는 실현 가능한 솔루션이 아닙니다.
따라서 보안 사고의 위험을 줄이려면 로컬 스토리지에 중요한 내용을 저장하지 않도록 해야 합니다.
많은 튜토리얼, 유튜브 비디오, 심지어 대학교와 코딩 부트 캠프에서 새로운 개발자들이 JWT를 로컬 스토리지에 인증 메커니즘으로 저장하도록 잘못 가르치고 있다.
모든 선생님들이 일생에 한 번쯤은 생각하는 것처럼,
우리는 정말 강의 계획표를 갱신해야 합니다.
그렇다면 로컬 스토리지에 대한 대안은 무엇입니까?
두 가지 대안이 있습니다
JWT를 로컬 저장소에 저장하는 대신 쿠키에 저장하십시오(권장하지 않음). 그 이유를 알아보려면 계속 읽어보십시오.)
다른 하나는 세션 및 쿠키를 사용하여 서버측 인증을 사용하는 것입니다(권장).
JWT를 함께 사용하는 것에 대한 대안이 있습니다.
The second option is recommended and tutorials can be found almost anywhere so I won’t be explaining why but instead why not the first option.
Storing a JWT in the cookies is perfectly OK and it has the advantage of not needing custom JS code to pass it to each HTTP request to your backend.
But in some situations, like when your API is also used by your mobile app and it requires the “Authorization Bearer xxx” header instead of a cookie or when you’re making HTTP requests to multiple backends but with same JWT, it’s convenient to have your JWT in localStorage instead.
This is correct but you want to store a JWT in a cookie — that’s fine.
BUT!!
The purpose of JWTs is to be stateless, right? Cookies are capped out at 4k, which means the JWT needs to be < 4k for this to work.
— Randall Degges
JWT의 목적은 무국적(statent)이 되는 거죠? 쿠키는 4k로 제한되는데, 이는 JWT가 < 4k가 되어야 이를 실행할 수 있다는 것을 의미
대부분의 상태 비저장 JWT는 4kb 이상입니다(이것은 확인하기가 매우 쉽습니다). 데이터베이스에 있는 사용자를 JWT로 가져와서 그 크기를 살펴보기만 하면 됩니다. 거의 모든 경우에 결과 JWT는 4KB 제한을 초과합니다.) 상황이 이렇다 보니, 당신은 본질적으로 로컬 스토리지를 사용하는 것으로 돌아갔습니다.
그렇게 하는 대신: 제가 추천한 대로 세션 쿠키를 사용하는 것이 어떨까요?
단점은 당신이 API 측에서 캐시를 관리해야 한다는 것이지만, 이것은 쉽게 할 수 있습니다.
JWT를 사용하더라도 취소를 처리하는 중앙 집중식 세션이 있어야 합니다.
JWT는 기본적으로 안전하지 않습니다. 인증/인증 데이터를 캐슁하기 때문에 속도 대 보안 균형을 유지하기 위해서는 어떤 상황에서도 해지 목록을 중앙에서 관리해야 합니다. 그렇지 않으면 권한/데이터가 허용되는 상황이 발생하게 됩니다. 좋지 않은 시나리오입니다.
마지막으로, 세션 쿠키를 사용하는 것이 더 빠르고 안전할 뿐만 아니라 개발자의 99%가 사용할 수 있는 훨씬 간단하고 안전합니다. 만약 당신이 당신이 무엇을 하고 있는지 알고 있고 기꺼이 타협할 수 있는 1%에 속한다면, 그것을 실행하라. 하지만 99%의 사람들에게는 좋지 않은 생각입니다.
— 란달 데게스
쿠키만 사용하는 것은 해결책이 아니지만, 타사 JavaScript 코드가 쿠키를 읽을 수 없도록 하는 쿠키의 "HTTP 전용" 매개 변수를 활성화하고 HTTPS를 통해서만 쿠키를 전송하는 보안 플래그를 활성화함으로써 XSS 공격을 방지하기 위한 추가 단계를 수행해야 합니다.
네! JWT를 도난당한 경우, 도둑은 JWT를 계속 사용할 수 있습니다. JWT를 받아들이는 API는 JWT 소스에 의존하지 않고 독립적으로 검증하므로 API 서버는 이것이 도난당한 토큰인지 알 방법이 없습니다! 이것이 JWT가 만료 값을 갖는 이유입니다. 그리고 이 값들은 짧게 유지된다. 일반적으로 JWT의 유출이 상당히 빨리 중지되도록 15분 정도 보관하는 것이 일반적입니다. 또한 JWT가 유출되지 않도록 주의하세요.
그렇기 때문에 JWT를 쿠키나 로컬 스토리지를 통해 클라이언트에 저장하지 않는 것도 매우 중요합니다. 이렇게 하면 악성 양식이나 스크립트로 프로그램이 CSRF & XSS 공격에 취약해지거나 쿠키 또는 로컬 저장소에 저장된 토큰을 사용하거나 도용할 수 있습니다.
어! 이거 복잡한 것 같은데. 내가 왜 좋은 세션 토큰을 고수하면 안 돼?
이것은 인터넷에서 고통스러운 토론입니다. 우리의 짧은 답변은 a) microservices b) 중앙 집중식 토큰 데이터베이스가 필요하지 않기 때문에 백엔드 개발자들이 JWT를 사용하는 것을 좋아한다는 것이다.
마이크로 서비스 설정에서 각 마이크로 서비스는 클라이언트로부터 받은 토큰이 유효한지 독립적으로 확인할 수 있습니다. 마이크로 서비스는 중앙 집중식 토큰 데이터베이스에 액세스할 필요 없이 토큰을 추가로 디코딩하고 관련 정보를 추출할 수 있습니다.
그렇기 때문에 JWT와 같은 API 개발자들과 (클라이언트 쪽에 있는) 우리는 그것을 어떻게 사용하는지 알아내야 한다. 하지만 좋아하는 단일 프레임워크에서 발행하는 세션 토큰을 사용할 수 있다면 바로 사용할 수 있으며 JWT가 필요하지 않을 것입니다!