이용자의 신원 정보가 포함된 쿠키는 일종의 서명과 같은 역할을 한다. 일상에서 서명은 서명자가 문서의 내용에 동의했다는 것을 함축한다. 이에 따라 서명된 문서는 효력을 갖게 되고, 이용자의 권한도 부여 받는다. 쿠키도 마찬가지이다. 이용자의 식별 정보가 포함된 쿠키는 클라이언트에서 보내진 요청이 이용자로부터 왔으며, 이용자가 동의했고, 따라서 요청에 이용자의 권한이 부여돼야함을 의미한다. 실생활과 밀접한 웹 서비스가 많아지고 있기 때문에, 서명을 신중하게 관리하는 것 만큼 중요한 웹 서비스의 쿠키도 잘 보관해야 한다.

서명과 관련된 범죄는 서명을 날조하거나, 서명된 문서를 위조하는 것 등이 있다. 이러한 범죄는 웹 해킹의 공격 기법들과도 대응되는데, 전자는 XSS를 통해 쿠키를 탈취하는 공격과 유사하고, 그리고 후자는 **교차 사이트 요청 위조(Cross Site Request Forgery, CSRF)**와 비슷하다.

서명된 문서를 위조하는 것은, 이미 서명된 문서의 내용을 조작하는 것을 말한다. 빈 종이에 서명하지 말아야 하는 것이 이러한 위험을 피하기 위함이다. 나중에 누군가 그 종이에 "나는 A에게 전재산을 양도한다." 따위의 문장을 적어서 내용을 위조해도, 서명으로 인해 효력을 가질 수 있기 때문이다.

CSRF는 위와 비슷하게 이용자를 속여서, 의도치 않은 요청에 동의하게 하는 공격을 말한다. 그럴듯한 웹 페이지를 만들어서 이용자의 입력을 유도하고, 이용자가 값을 입력하면 이를 은행이나 중요 포털 사이트 등으로 전송하여 마치 이용자가 동의한 것 같은 요청을 발생시킨다. 만약, 이용자가 "자동 로그인"등의 기능을 사용하여 브라우저에 세션 쿠키를 저장하고 있었다면, 실제로 계좌 이체가 발생하거나 비밀번호 초기화가 이뤄질 수도 있다.


Cross Site Request Forgery (CSRF)

Cross Site Request Forgery (CSRF)

CSRF는 사이트 간 요청 위조. 이용자가 자신의 의지와는 무관하게 공격자가 의도한 행위를 특정 웹 사이트에 요청하게 만드는 공격이다.

웹 서비스는 쿠키 또는 세션을 사용해서 이용자를 식별한다. 임의 이용자의 쿠키를 사용할 수 있다면, 이는 곧 임의 이용자의 권한으로 웹 서비스의 기능을 사용할 수 있음을 의미한다. CSRF는 임의 이용자의 권한으로 임의 주소에 HTTP 요청을 보낼 수 있는 취약점이다. 공격자는 임의 이용자의 권한으로 서비스 기능을 사용해 이득을 취할 수 있다. 예를 들어, 이용자의 계정으로 임의 금액을 송금해 금전적인 이득을 취하거나 비밀번호를 변경해 계정을 탈취하고, 관리자 계정을 공격해 공지사항 작성 등으로 혼란을 야기할 수 있다.

아래 코드는 송금 기능을 수행하는 엔드포인트 코드 예시로, CSRF 취약점이 존재한다. 코드를 살펴보면, 이용자로부터 예금주와 금액을 입력 받고 송금을 수행한다. 이때 계좌 비밀번호, OTP 등을 사용하지 않기 때문에 로그인한 이용자는 추가 인증 정보 없이 해당 기능을 이용할 수 있다.

# 이용자가 /sendmoney에 접속했을때 아래와 같은 송금 기능을 웹 서비스가 실행함.
@app.route('/sendmoney')
def sendmoney(name):
        # 송금을 받는 사람과 금액을 입력받음.
        to_user = request.args.get('to')
	amount = int(request.args.get('amount'))
	
	# 송금 기능 실행 후, 결과 반환	
	success_status = send_money(to_user, amount)
	
	# 송금이 성공했을 때,
	if success_status:
	    # 성공 메시지 출력
		return "Send success."
	# 송금이 실패했을 때,
	else:
	    # 실패 메시지 출력
		return "Send fail."
GET /sendmoney?to=dreamhack&amount=1337 HTTP/1.1
Host: bank.dreamhack.io
Cookie: session=IeheighaiToo4eenahw3

Cross Site Request Forgery 동작

CSRF 공격에 성공하기 위해서는 공격자가 작성한 악성 스크립트를 이용자가 실행해야 한다. 이는 공격자가 이용자에게 메일을 보내거나 게시판에 글을 작성해 이용자가 이를 조회하도록 유도하는 방법이 있다. 여기서 말하는 악성 스크립트는 HTTP 요청을 보내는 코드이다.

CSRF 공격 스크립트는 HTML 또는 Javascript를 통해 작성할 수 있다. 아래 사진 및 코드는 HTML으로 작성한 스크립트의 예시이다. 이미지를 불러오는 img 태그를 사용하거나 웹 페이지에 입력된 양식을 전송하는 form 태그를 사용하는 방법이 있다. 이 두 개의 태그를 사용해 HTTP 요청을 보내면 HTTP 헤더인 Cookie에 이용자의 인증 정보가 포함된다.

09e96a6b5d141052eeec45a5848e5c11bebba94e2f5a9ce4c8968abaf44f8888.png

아래 코드img 태그를 사용한 스크립트의 예시이다. 해당 태그는 이미지의 크기를 줄일 수 있는 옵션을 제공한다. 이를 활용하면 이용자에게 들키지 않고 임의 페이지에 요청을 보낼 수 있다.

<img src='<http://bank.dreamhack.io/sendmoney?to=Dreamhack&amount=1337>' width=0px height=0px>