목차
xss
크로스 사이트 스크립팅 (XSS)은 공격자가 웹사이트에 악성 클라이언트 사이드 코드를 삽입할 수 있도록 하는 보안 취약점 공격입니다. 이 악성 코드는 피해자에 의해 실행되며 공격자가 접근 제어를 우회하고 사용자로 위장할 수 있게 만들어 줍니다.
# src에 의미없는 값을 넣어서 일부러 에러를 터뜨려 alert를 콜하는 이미지태그입니다.
# 만약에 alert가 아닌 웹사이트의 개인정보들을 탈취할 수 있는 js코드를 넣으면 어떻게 될까요?
<img src='x' onerror='alert("공격")'>
escape를 통한 방어를 하는 react
그렇다면 우리가 이제까지 생각없이 react에서 작성했던 코드들은 어떻게 그것들을 방어하고 있는 것일까?
XSS 방어 방법에 여러가지가 있겠지만 대표적인 방법은 escape를 시키는 방법이 있습니다. 그러므로 태그를 삽입해도 태그처럼 작동하지 않고 일반 스트링으로 보여지게 됩니다.
# escape을 하게 되면 아래처럼 변환됩니다:
< becomes <
> becomes >
# script 태그는 아래처럼 변환됩니다.
<script> -> <script>
dangerouslySetInnerHTML
dangerouslySetInnerHTML은 브라우저 DOM에서 innerHTML을 사용하기 위한 React의 대체 방법이다.
일반적으로 코드에서 HTML을 설정하는 것은 사이트 간 스크립팅 공격에 쉽게 노출될 수 있기 때문에 위험하다.
따라서 React에서 직접 HTML을 설정할 수는 있지만, 위험하다는 것을 상기시키기 위해 dangerouslySetInnerHTML을 작성하고 __html 키로 객체를 전달해야 한다.
그렇다면 위험을 상기시키는 것 말고 실질적으로 막을 방법이 없을까?
dompurify가 그 역할을 해준다.
DOMPurify를 통한 안전한 HTML 처리
DOMPurify는 XSS 공격 시도를 포함할 수 있는 코드를 제거하고, 안전하게 사용할 수 있는 HTML만을 남긴다.
https://cure53.de/purify 이 사이트에서 시도해 볼 수 있다.
CSRF
CSRF란, Cross Site Request Forgery의 약자로, 한글 뜻으로는 사이트간 요청 위조를 뜻합니다.CSRF는 웹 보안 취약점의 일종이며, 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위(데이터 수정, 삭제, 등록 등) 을 특정 웹사이트에 요청하게 하는 공격입니다.예를 들어, 피해자의 전자 메일 주소를 변경하거나 암호를 변경하거나 자금이체를 하는 등의 동작을 수행하게 할 수 있습니다.특성에 따라, 공격자는 사용자의 계정에 대한 완전한 제어권을 얻을 수 있을 수도 있습니다.
1. 사용자는 보안이 취약한 서버에 로그인한다.
2. 서버에 저장된 세션 정보를 사용할 수 있는 session ID가 사용자의 브라우저 쿠키에 저장된다.
3. 공격자는 사용자가 악성 스크립트 페이지를 누르도록 유도한다.악성 스크립트 페이지를 누르도록 유도하는 방식은 아래와 같은 방식들이 있다.- 게시판이 있는 웹사이트에 악성 스크립트를 게시글로 작성하여 사용자들이 게시글을 클릭하도록 유도- 메일 등으로 악성 스크립트를 직접 전달하거나, 악성 스크립트가 적힌 페이지 링크를 전달한다.
4. 사용자가 악성 스크립트가 작성된 페이지 접근시 웹 브라우저에 의해 쿠키에 저장된 session ID와 함께 서버로 요청된다.
5. 서버는 쿠키에 담긴 session ID를 통해 해당 요청이 인증된 사용자로부터 온 것으로 판단하고 처리한다.
그러면 의문점이 생긴다. cors 설정을 통해 위조된 사이트의 도메인을 확인하면 알아서 막히는게 아닌것인가?
CORS는 브라우저의 보안 정책 중 하나이며, _JavaScript로 cross-origin 요청을 보낼 때만 적용된다.
브라우저가 자동으로 전송하는 HTML 폼 요청이나 <img>, <script> 요청 등에는 CORS가 적용되지 않는다.
이를 이해하기 위해서는 sop를 알아보자.
Same-origin Policy란?
스크립트에 적용되는 정책이며, 스크립트 내에서 다른 리소스, 데이터를 요청할 때 요청지와 데이터 출처가 Same-origin이 아니면 막는 정책이다.
현재 스크립트를 실행하고 있는 주소와 (프로토콜, 호스트, 포트)가 동일한 주소를 Same-origin으로 판단한다.
이는 브라우저가 document.domain을 보고 판단함.
좀 더 정확히는, Cross-origin read를 막는다.
교차 출처 쓰기는 보통 허용한다.
Cross-origin으로의 링크, 리다이렉트, form submit 등
교차 출처 삽입은 보통 허용한다.
- HTML 태그로 가져오는 항목(
교차 출처 읽기는 보통 불허 (ajax 등)
- 하지만, 종종 교차 출처 삽입 과정에서 읽기 권한이 누출된다.
- 예를 들면 삽입한 이미지의 크기나 삽입한 <script>의 행동 등을 읽을 수 있다.
- (*그래서 JSONP로 우회가 가능한 것)
왜 script에서 Cross-origin read를 막는가?
단순히 Cross-origin으로 데이터 보내는걸 막고자 했다면 form submit도 막았어야 한다.
마찬가지로 Cross-origin에서 데이터 가져오는 것 자체를 막고자 했다면, submit이나 삽입도 막았어야 한다.
그렇다면 왜 읽기만 불허할까?
읽기를 불허한다는건, script 내에서 ajax 등을 이용해서 페이지 이동 없이 Cross-origin에서 데이터 받는 것을 막겠다. 라는 의미
사실은 브라우저가 도메인 별로 쿠키를 관리하고, 해당 도메인에 접근 시 맞는 쿠키를 알아서 꺼내준다는 점과 관련이 있다.
csrf를 막는 방법
1. origin 헤더를 통해 출처 사이트를 검증하여 막는다.
하지만 아래와 같은 단점이 있다.
- 단순 요청(simple request) 은 preflight 없이 바로 서버로 전송됨.
- <form method="POST" action="...">
- <img src="...">, <script src="...">
- 이들은 Origin 헤더가 없을 수도 있음 또는 CSRF 공격에 사용될 수 있음.
- 이미지, 스크립트 태그로 발생하는 요청은 SOP를 우회해서 전달될 수 있음. 응답은 공유되지 않지만, 요청은 전달되므로 사이드 이펙트가 발생할 수 있는 API는 보호되지 않으면 위험함.
- **일부 브라우저나 환경(플러그인, 구형 브라우저)**에서는 Origin을 조작할 수 있음.
- 예: 과거 Flash, 일부 브라우저 버그 등
- **커맨드라인 툴(curl, Postman 등)**에서는 Origin을 마음대로 설정 가능.
- 이는 REST API가 외부에서도 접근 가능한 경우, 더욱 위험함.
2. CSRF 토큰을 통해 막기
CSRF 토큰은 특정 요청이 사용자가 의도한 것인지 확인하기 위해 사용된다. 즉, 요청이 사용자의 브라우저에서 실제로 발생했는지 확인하는 것이다.
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as csurf from 'csurf';
import * as cookieParser from 'cookie-parser';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(cookieParser());
app.use(csurf({ cookie: true }));
await app.listen(3000);
}
bootstrap();
import { Controller, Get, Req, Res } from '@nestjs/common';
import { Request, Response } from 'express';
@Controller()
export class AppController {
@Get('csrf-token')
getCsrfToken(@Req() req: Request, @Res() res: Response) {
res.cookie('XSRF-TOKEN', req.csrfToken());
res.send({ csrfToken: req.csrfToken() });
}
}
위와 같이 cookie에 담아서 주는 것은 알겠는데 굳이 accessToken이 있는데 왜 또 써야 하는지 의문점이 생길 수 있다.
답은 간단하다.
accessToken을 쿠키에 저장하는 방식이 취약하기 때문에 그때 써주면 된다.
'CS' 카테고리의 다른 글
[NodeJs] os 관점에서 더 자세히 알아보자 (0) | 2025.04.05 |
---|---|
Restful한 api는 무엇일까 (0) | 2025.04.02 |
[Cs] 파일 업로드에 대해 자세히 알아보자 (0) | 2025.02.05 |
NodeJs 에 대해 알아보자 (0) | 2025.01.06 |
웹 서버와 WAS의 차이를 살펴보자 (0) | 2024.11.17 |