기술나눔

프론트엔드 인터뷰 질문 50(어떤 일반적인 프론트엔드 보안 조치가 CSRF 공격을 예방할 수 있습니까?)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

여기에 이미지 설명을 삽입하세요.
CSRF(교차 사이트 요청 위조) 공격을 방지하기 위해 프런트 엔드 개발에서 다음과 같은 일반적인 보안 조치를 취할 수 있습니다.

1. CSRF 토큰 사용

이것은 가장 일반적으로 사용되는 방어 메커니즘 중 하나입니다.

  • 토큰 생성: 사용자가 로그인한 후 서버는 예측할 수 없는 임의의 CSRF 토큰을 생성하여 서버 측에 저장하는 동시에 Set-Cookie 헤더를 통해 클라이언트로 전송되어 사용자의 쿠키에 저장됩니다.

  • 양식 내장 토큰: 보호가 필요한 각 HTML 양식에 숨겨진 필드(<input type="hidden">), 해당 값은 쿠키에서 읽은 CSRF 토큰으로 설정됩니다.

  • 검증토큰 : 양식이 제출되면 백엔드는 양식 데이터와 쿠키의 토큰을 수신합니다(동일 출처 정책으로 인해 브라우저는 자동으로 쿠키를 보냅니다). 서버 측은 양식의 토큰이 서버 측 또는 세션에 저장된 토큰과 일치하는지 확인합니다. 일치하지 않는 경우 요청이 거부됩니다.

2. HTTP 리퍼러 및 원본 헤더 확인

Referer와 Origin이 변조되거나 누락될 수 있으므로 완전히 신뢰할 수는 없지만 일부 시나리오에서는 여전히 보조 수단으로 사용될 수 있습니다.

  • 추천인 확인 : 요청이 예상 도메인 이름에서 시작되었는지 확인하려면 HTTP 요청 헤더의 Referer 필드를 확인하세요. 그러나 이 방법에는 제한이 있습니다. 예를 들어 HTTPS에서 HTTP로의 다운그레이드 요청에서는 리퍼러가 전송되지 않습니다.

  • 원산지 헤더 확인: Referer와 유사하게 Origin 헤더는 요청 소스에 대한 정보를 제공하지만 XMLHttpRequest 또는 Fetch API를 사용할 때만 전송됩니다.

3. SameSite 쿠키 속성을 사용하세요.

사이트 간 액세스가 필요하지 않은 쿠키의 경우 SameSite 속성을 설정하여 보안을 강화할 수 있습니다.

  • SameSite=Lax: 쿠키는 동일한 사이트 요청에서만 전송되며 CSRF로부터 부분적으로 보호됩니다.
  • SameSite=엄격함: 쿠키는 동일한 사이트 및 동일한 페이지 탐색 내에서만 전송되므로 더 강력한 보호 기능을 제공하지만 예상되는 일부 하위 도메인 간 기능에 영향을 미칠 수 있습니다.
  • SameSite=없음: 최신 브라우저의 요구 사항에 적응하기 위해 크로스 사이트가 필요한 쿠키에 대해 Secure 속성과 함께 사용해야 합니다.

4. 사용자 정의 요청 헤더 확인

AJAX 요청에 사용자 정의 HTTP 헤더를 추가합니다(예:X-Requested-With: XMLHttpRequest ), 그런 다음 서버 측에서 이 헤더의 존재와 값을 확인합니다. JavaScript는 XMLHttpRequest의 헤더를 자유롭게 설정할 수 있지만 일반적인 양식 제출은 그렇지 않기 때문에 스크립트에 의해 시작된 요청을 구별할 수 있습니다.

샘플 코드(CSRF 토큰 구현):

서버측(의사코드):

// 生成并设置Token
function generateCsrfToken() {
    return crypto.randomBytes(32).toString('hex');
}

app.post('/login', (req, res) => {
    const token = generateCsrfToken();
    res.cookie('csrfToken', token, { httpOnly: true, secure: true, sameSite: 'strict' });
    // 存储token到session或其他存储机制
});

app.post('/submitForm', (req, res) => {
    if (req.body.csrfToken === req.cookies.csrfToken) {
        // 请求合法,处理逻辑...
    } else {
        // CSRF攻击检测,拒绝请求
        res.status(403).send('Forbidden');
    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

프런트엔드 HTML:

<form action="/submitForm" method="POST">
    <!-- 其他表单字段... -->
    <input type="hidden" name="csrfToken" value="{{csrfToken}}">
    <button type="submit">Submit</button>
</form>
  • 1
  • 2
  • 3
  • 4
  • 5

위 코드는 예시일 뿐이며, 실제 애플리케이션은 사용되는 백엔드 프레임워크와 언어에 따라 조정되어야 합니다.