실제 유저가 의도하지 않은 요청을 서버에 보내는 것.
ex) 사용자가 다른 웹 사이트에 이미 로그인되어 있을 때, 해당 사용자의 인증된 상태를 이용하여 악의적인 요청을 보내는 것입니다. 이를 통해 공격자는 사용자의 계정으로 원치 않는 행동을 수행하게 됩니다.
웹 브라우저 비동기 지원
웹 브라우저 동기 요청 : FORM
웹 브라우저 비동기 요청 : AJAX

웹 서버에서 클라이언트(웹 브라우저 등)가 이전에 어떤 페이지에서 왔는지 확인하는 데 사용되는 메커니즘이다.
브라우저가 서버로 referer라는 헤더값을 설정해서 보내면 서버는 referer를 참조함으로써 현재 페이지가 어떤 페이지에서 요청되었는지를 확인할 수 있다. 그럼으로써 어디서 방문자가 왔는지를 파악할 수 있다.
로그분석을 할 때, 우리 사이트로의 유입이 어떤 검색서비스를 이용한 것인지 알고자할 때 바로 이 referer를 분석한다고 보면 된다. 이것이 일반적인 로그분석기이다.
예를들어, http://www.test.com/1.html 이라는 웹페이지에 있는 링크를 클릭하여 http://www.power.com/2.html 으로 이동했을 때 referer는 http://www.test.com/1.html 이 된다.
컴퓨터와 인간을 구별하기 위한 완전한 자동화된 튜링 테스트.
웹 양식이나 로그인 페이지 등에서 사용자가 실제 사람인지 자동화된 봇인지를 확인하기 위해 사용한다.
많은 웹 프레임워크 및 언어에는 CAPTCHA를 쉽게 구현할 수 있도록 도와주는 라이브러리가 있다.
ex) Google reCAPTCHA, hCaptcha, Securimage
서버에 들어온 요청이 실제 서버에서 허용한 요청이 맞는지 확인하기 위한 토큰.

사용자가 회원가입 페이지를 요청하고 서버가 응답해주는 페이지가 나타나는게 일반적이다. 그런데 스프링 시큐리티가 해당 페이지에 CSRF토큰을 자동으로 심는다. CSRF방어 기능은 Spring Security 3.2.0 이후부터 지원된다고 한다. 따라서 CSRF토큰을 설정해주지 않으면 해당에러가 나타나는 것이다.
내 이전 프로젝트 예시
코드를 입력하세요
origin은 스키마 + 도메인 + 포트였다. 이중에서 하나라도 같으면 same-origin, 다르면 cross-origin이 되는 것이다.
site는 eTLD(effective TLD)와 SLD(Second Level Domain)의 조합이라고 해서 아래 그림과 같이 된다.

SLD가 다른 경우를 제외하고 포트, 스키마, 서브도메인이 달라져도 sage-site로 취급한다.
SLD는 예를 들어, mozilla.org에서 SLD는 mozilla이고 TLD는 org이다.
| 출처 A | 출처 B | 출처 A와 B가 'same-site'인지 'cross-site'인지에 여부 |
|---|---|---|
| https://www.example.com:443 | https://www.evil.com:443 | cross-site: 서로 다른 도메인 |
| "" | https://login.example.com:443 | same-site: 서로 다른 하위 도메인은 중요하지 않음 |
| "" | http://www.example.com:443 | cross-site: 다양한 스키마 |
| "" | https://www.example.com:80 | same-site: 다른 포트는 중요하지 않음 |
| "" | https://www.example.com:443 | same-site: 일치검색 |
| "" | https://www.example.com | same-site: 포트는 중요하지 않습니다 |
😫 request 요청이 same-site, cross-site, same-origin 중 무엇인지 구별하는 법
크롬 브라우저는 요청 시 Sec-Fetch-Site http 헤더를 함께 보낸다. Sec-Fetch-Site에는 아래와 같은 값들이 있다. 단, schemeful-same-site는 Sec-Fetch-Site 헤더로는 알 수 없다.
AJAX 보안 정책으로 SOP가 있다. 웹 브라우저에서 HTTP Resource를 갖고오기 위한 모든 HTTTP 요청은 기본적으로 SOP정책을 갖는다.
같은 출처에서만 리소스를 공유할 수 있도록 하는 규칙으로 데이터 가져올 때 같은 도메인인지를 본다.
결국 Same-Origin인지를 본다.
HTTP Resource를 갖고 오기 위한 모든 HTTP 요청은 기본적으로 SOP.
하지만 브라우저는 스크립트 혹은 이미지 등의 HTTP Resource는 외부에서 정보를 가져올 상황이 존재하며, SOP는 부분적으로 Cross-Origin이 허용된다.
하지만 POST 방식의 경우 서버 상태를 바꿀 수 있기 때문에 보안 위험성이 존재한다.
AJAX는 표준 기술이 아님에도 사실상 표준으로 막으면 API 호출이 불가능하다.
이 AJAX에 대한 추가 보안 정책이 CORS이다.
출처에 대한 구분은 브라우저가 한다.
추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 App이 다른 출처(Protocal, Domain, Port)의 리소스에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 것.
AJAX를 통해 요청했을 때 허용된 call인지 허용되지 않은 call인지를 판단한다.
웹 브라우저에서 AJAX를 통한 악의적 요청(CSRF)을 방지.
Cross-Origin이 되면 브라우저에서는 보안때문에 HTTP 요청을 제한한다.
🔆 결과적으로 CORS 를 통해 모든 CSRF 공격을 방지할 수 있는건 아니라는 것
출처가 다른 두 App이 통신하면 사용자 공격에 취약하다. 제약이 없다면, 해커가 CSRF(Cross-Site Request Forgery)나 XSS(Cross-Site Scripting) 등의 방법을 이용해서 우리가 만든 어플리케이션에서 해커가 심어놓은 코드가 실행하여 개인 정보를 가로챌 수 있다.
간단 정리
SOP 정책을 사용하면 좋긴 하나 출처가 다른 곳과 통신을 해야 하는 경우가 있다. 이 경우에는 SOP 정책을 벗어나기 때문에 CORS를 사용한다.
결국 CORS는 해결법이다.
서버는 브라우저로부터 어떤 요청만 받을지 3가지 CORS 헤더 설정을 통해 웹 브라우저가 호출가능한 요청을 제약할 수 있다.
브라우저는 요청 헤더에 Origin이라는 필드에 출처를 함께 담아 보낸다.
서버는 이 요청에 대한 응답으로 Access-Control-Allow-Origin 이라는 필드를 추가하고 값으로 "이 리소스를 접근하는 것이 허용된 출처 url"을 내보낸다.
요청 헤더의 Origin과 응답 헤더의 Access-Control-Allow-Origin을 비교한다.


비교해서 차단할지 말지를 결정하는데 유효하지 않다면 이 응답을 사용하지 않고 버린다. (CORS에러)
위와 같은 그림에서는 같기 때문에 유효하니 다른 출처의 리소스를 문제없이 가져온다.
허용된 Origin이란 특정 출처로부터의 HTTP 요청이 서버에서 수락되는 출처를 말한다. 서버에서 허용되야 클라이언트의 웹 브라우저에서 해당 출처로의 리소스 요청이 가능해진다.
클라이언트에서 HTTP요청의 헤더에 Origin을 담아서 전달한다.
예시
Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Origin: https://example.com, https://anotherdomain.com
클라이언트가 서버로 보낼 수 있는 HTTP 요청 메서드를 나타낸다. 웹 브라우저는 브라우저가 보낼 수 있는 메서드를 제한하고 서버는 허용할 메서드를 설정해야 한다.
예시
클라이언트 (사전 알림) : "나는 POST 메서드를 사용해서 요청을 보낼거야"
Access-Control-Request-Method: POST
예시
서버 : "클라이언트야 POST 메서드 사용할 수 있도록 허용할게."
클라이언트의 요청이나 사전 검사 요청에서 사용된 HTTP 메서드를 기반으로 설정.
Access-Control-Allow-Methods: POST
브라우저가 실제 요청을 보내기 전에 서버에게 특정 요청이 안전하게 보내질 수 있는지 사전에 확인하기 위한 요청이다.

fech API를 사용하여 브라우저에게 리소스를 받아오려 하면 브라우저는 서버에게 사전 요청을 보냄.
서버는 사전 요청에 대한 응답으로 현재 어떤 것을 허용하고, 어떤 것을 금지하고 있는지에 대한 정볼르 응답 헤더에 담아서 브라우저에게 전달.
실제 요청 전에 OPTION 메서드를 사용하여 서버에게 허용된 메서드, 헤더, 출처 등을 물어본다.
'Access-Control-Request-Method', 'Access-Control-Request-Headers' 를 보낸다.
서버는 이 요청에 대해 'Access-Control-Allow-Origin', 'Access-Control-Allow-Methods', 'Access-Control-Allow-Headers' 등을 헤더에 포함하여 응답.
예시
사전 검사 요청
OPTIONS /resource HTTP/1.1
Host: example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type
서버 응답
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://client.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type

서버에게 클라이언트가 사용하려는 출처, 메서드, 헤더 등을 알려주어 서버는 이를 검증하고 혀용 여부를 결정한다. 그러면 다른 출처에서의 요청은 차단할 수 있고 클라이언트가 출처, 메서드, 헤더등을 사용하여 안전하게 요청을 하는지를 알 수 있다.
Preflight 요청에서 서버로부터 허용된 Origin 값이 요청으로 보낸 Origin 값과 다르다면 브라우저는 CORS 정책 위반으로 처리하지만 응답은 정상적으로 처리된다. 이는 Preflight 요청에 대한 응답을 받은 이후에 판단되기 때문에 CORS 에러는 요청의 성공 여부와 관련이 없다.
사전 요청없이 브라우저에서 서버로 요청을 보내는 형태다.

이러한 경우
허용된 메서드는 GET, HEAD, POST 중 하나여야 한다.
허용된 헤더
허용된 컨텐츠 타입
POST /api/data HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
key1=value1&key2=value2
POST 메서드 사용, 허용된 Content-Type 사용.
따라서 Simple Request.
CSRF 는 Cross-Site 이기때문에 동일 사이트 (Same-Site) 에 대한 공격은 포함하지 않을거같아요. 근데 그것도 스크립트로 심어서 충분히 동일 사이트라도 의도치 않은 API 를 공격할수있다고 생각하긴합니다.
CSRF 방어로 Referrer 가 있다고 질문주셨었는데, 그것도 결국 CSRF 공격은 Cross-Site 라는걸 가정하는거니까요. Same-Site 에 대한 API 공격 (자바스크립트 인젝션 등) 은 개념적으로는 CSRF 에 포함되지 않는게 맞습니다.
Q2. 웹 브라우저와 웹 서버 간에 교환이 이루어 질 때는, 웹 페이지와 데이터의 교환이 이루어지는데, 웹 서버와 웹 서버간의 교환일 때도 웹 페이지와 데이터 모두 교환이 일어나는지 데이터의 교환만 이루어지는지 궁금합니다.
A2. 웹 서버와 웹 서버간에 웹 페이지를 교환할 필요가 있을지 한번 생각해볼까요. 웹 페이지를 읽기 위해서는 특수 언어로 되어있기에 리더기격인 웹 브라우저가 필요하다고 말씀드렸습니다.
웹 서버는 기본적으로 웹 페이지를 읽거나 분석할 수 없으니 (웹 브라우저가 아니니) 말씀주신 웹 서버 - 웹 서버간 웹 페이지 교환 케이스는 없다고 보는게 맞겠습니다.
그런데 또 모르는 것이 웹 서버가 웹 서버한테 웹 페이지를 전달하고 그걸 그대로 웹 브라우저에게 전달할수도 있긴하니까요. 그런 경우를 한번도 본적은 없습니다만, 그렇다고 아예 하지말라, 절대 틀린거다 라고 강력하게 얘기드리긴 어렵겠어요
CORS 는 웹 브라우저와 웹 서버간의 통신에서 발생하는 문제 해결 정책이라
웹 서버와 웹 서버간의 통신에서는 CORS 는 전혀 고려되지 않습니다.
CORS 는 웹 브라우저의 취약성 때문에 적용되는 정책이기 때문이죠
웹 브라우저와 웹 서버는 다른 특성을 가졌기에 이런 차이가 발생합니다.
결국 웹 브라우저와 웹 서버는 차이가 꽤 있다고 아시면 됩니다.
Q3. Referer Header를 통해 대부분의 CSRF 공격을 방지할 수 있다는 글을 보았습니다. 이때 Referer Header에 현재 요청이 발생한 페이지의 URL을 담아서 보내고 이를 검사해 지정된 페이지에서 오지 않은 요청을 드랍시키는 방식이라고 이해했습니다.
A3. CSRF는 Cross-Site 에서 이미 웹 브라우저를 통해 보고 있는 사이트 도메인과 다른 도메인에게 요청을 보내는 이슈이기에, 해당 사이트에 공격자가 직접 스크립트를 심어 유저가 보고있는 오늘의집과 전혀 상관없는 옥션 API 를 호출하는 것을 Referer로 간단히 막을 수 있습니다.
공격자가 심은 스크립트가 오늘의집 사이트에서 옥션 API 호출한다면 그것이 CSRF 공격이고 이는 Referer 로 쉽게 막아내어집니다.
Q4. Referer 헤더를 이용한 방지와 Origin을 비교하는 Same-site가 다른건가요? 그리고 지정된 페이지에서 오지 않은 요청을 드랍시킨다는 것이 서버에서 지정해놓지 않은 Origin에서 온 요청은 무시한다는 것과 같아보이는데 CORS랑 다른 건가요?
A4. Referer 헤더를 이용한 방지는 CORS는 웹 브라우저가 Origin 과 Allow-Origin 을 비교하는것이고, Referer 체크는 웹 서버가 하는겁니다. 예를 들면, 옥션 API 웹 서버가 "읭? Referer 가 오늘의집이네? 뭥미? 버려야지." 하는거에요.
Origin을 비교하는 Same-site의 경우는 쿠키 설정에서의 SameSite 는 CSRF 가 발생했을 때 오늘의집에서 옥션 API 호출할때는 옥션에서 인증받았던 쿠키가 있더라도 "오늘의집 != 옥션" 이니까 쿠키를 보내지 말라는 의미입니다.
Referer 설명에서 지정된 페이지에서 오지 않는 요청을 드랍시킨다는 것은 옥션 API 웹 서버가 "읭? Referer 가 오늘의집이네? 뭥미? 버려야지." 를 기억하시면됩니다.
다른 의미로 Host 와 Referer 가 일치한다는건 Cross-Site 가 아니라는 의미기도하죠.
Reference
🔗 https://developer.mozilla.org/ko/docs/Web/HTTP/CORS - 교차 출처 리소스 공유 (CORS)
🔗 https://junhyunny.github.io/information/security/spring-boot/spring-security/cross-site-reqeust-forgery/ - CSRF(Cross-Site Request Forgery) 공격과 방어
🔗 https://velog.io/@jupiter-j/CSRF%ED%86%A0%ED%81%B0%EC%9D%B4%EB%9E%80 - CSRF토큰이란?
🔗 https://nordvpn.com/ko/blog/csrf - 크로스 사이트 요청 위조란?
🔗 https://roseline.oopy.io/dev/til-same-site-vs-same-origin - site와 origin 차이
🔗 https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-CORS-%F0%9F%92%AF-%EC%A0%95%EB%A6%AC-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95-%F0%9F%91%8F#%F0%9F%8F%B7%EF%B8%8F_%EA%B0%99%EC%9D%80_%EC%B6%9C%EC%B2%98%EC%99%80_%EB%8B%A4%EB%A5%B8_%EC%B6%9C%EC%B2%98_%EA%B5%AC%EB%B6%84_%EA%B8%B0%EC%A4%80 - CORS 완전 정리
추가
🔗 https://velog.io/@jupiter-j/%EC%97%90%EB%9F%AC-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0-%EC%97%90%EB%9F%AC-403-404 - 시큐리티 에러 403, 404