본문 바로가기

24년 1학기 학교공부/네트워크웹보안

[NW] CSRF Attack

목차

    728x90
    반응형
    SMALL
    2024학년도 1학기 충남대학교 장진수 교수님의 네트워크 및 웹 보안 수업 정리자료입니다.

     

     

     

     

    Same-Site Request와 Cross-Site Request

     

    - Same-Site Request : 웹사이트 A의 페이지에서 웹사이트 A로 전송하는 HTTP request
    - Cross-Site Request : 웹사이트 A의 페이지에서 웹사이트 B로 전송하는 HTTP request

     

    예를 들어 인스타그램 웹페이지에서 페이스북 링크를 발견하고 이를 클릭하여 페이스북으로 이동하는 경우, 인스타그램 웹페이지가 페이스북에게 HTTP request를 전송한다. 이런 경우의 request를 Cross-site Request라고 말한다.

     

     

    이때 HTTP request에는 해당 request를 전송하는 브라우저의 cookie가 저장되어있다. 이때 cookie에 저장되는 대표적인 정보에는 사용자가 특정 서버에 로그인할 때 저장되는 Session ID가 있다. 일반적으로 다음 과정을 통해 cookie에 Session ID가 저장된다.

    1. 사용자가 로그인을 하면, 서버는 인증된 사용자의 정보를 세션에 저장하고, 이를 찾을 수 있는 Session ID를 생성한다.
    2. 서버는 브라우저가 위 정보를 사용할 수 있도록, Set-Cookie 헤더에 Session ID를 담아서 전달한다.
    3. 브라우저는 전달받은 Session ID를 cookie에 저장한다.
    4. 브라우저가 HTTP request를 전달할 때, cookie도 함께 전달되므로 Session ID가 서버로 전달된다.
    5. 서버는 cookie로 전달받은 Session ID를 보고, request가 인증된 사용자로부터 왔는지를 확인한다.

    웹사이트 A에서 A로 HTTP request 및 cookie를 전송하는 same-site request의 경우, 위 과정이 위험 없이 동작할 수 있다.

     

    하지만 웹사이트 A에서 B로 HTTP request를 전송하는 cross-site request의 경우를 생각해보자. 웹사이트 B가 만약 악의적으로 만들어진 해커의 사이트라면 해커는 HTTP request와 함께 전달된 cookie에 의해 Session ID를 훔칠 수 있게 된다. 이 Session ID는 웹사이트 A에서 본인의 사이트에 인증된 사용자인지를 확인하는 용도로 사용되기 때문에, 해커가 훔친 Session ID를 cookie에 포함시킨 HTTP request를 웹사이트 A에게 전송함으로써 인증된 사용자가 할 수 있는 행동을 수행할 수 있게 된다. 즉 서드파티 웹사이트가 same-site request와 완전히 동일하게 request를 위조하는 것이 가능해지는 것이다.

     

    웹사이트 A는 HTTP request를 받게 되더라도, 이 요청이 본인 웹사이트로부터 온 same-site request인지, 혹은 타 사이트로부터 온 정상적인 cross-site request인지, 위와 같이 해커가 훔친 cookie를 사용하여 전달한 cross-site request인지 구별할 방도가 없다.

     

     

    이처럼 cross-site request의 취약점을 이용한 공격을 Cross-Site Request Forgery (CSRF)라고 부른다.

     

     

     

     

    CSRF Attack 

    공격자는 타겟 웹사이트로 cross-site request를 위조할 수 있는 웹페이지를 만들고, 피해자가 타겟 웹사이트에 로그인 한 이후, 본인의 악성 웹사이트를 방문하도록 유도한다.

     

    1. HTTP GET requests : data가 URL에 들어있다.

    2. HTTP POST requests : data가 HTTP request 내부의 data 필드에 들어있다.

     

    1. 사용자에게 송금 기능을 제공하는 온라인 뱅킹 웹사이트 www.bank32.com 가 있다.

    2. 사용자가 웹 어플리케이션에 로그인하고, 검증된 사용자를 식별하는 고유의 세션 쿠키를 갖는다.

    3. 500달러를 사용자의 계좌에서 계좌 3220으로 송금하는 HTTP request URL은 다음과 같다.

    http://www.bank32.com/transfer.php?to=3220&amount=500

    4. 공격을 수행하려면, 희생자의 세션 쿠키를 request에 넣기 위해 희생자의 기계로부터 위조된 request를 보내야한다.

    5. 공격자는 reqeust를 유발하는 코드의 일부분을 공격자 웹 페이지의 JavaScript 코드 내에 넣을 수 있다.

    6. img나 iframe과 같은 HTML tag들은 src 특성에 명시된 URL에 GET request를 보내고, 응답으로 이미지나 웹페이지를 받을 수 있다.

     

     

     

     

    CSRF Attack Example

    Elgg란 소셜 네트워킹을 위한 오픈소스 웹 어플리케이션이다. VM에서는 CSRF 대응책이 실행되지 않는다.

    타겟 웹사이트 : http://www.csrflabelgg.com

    공격자 웹사이트 : http://www.csrflabattacker.com

    두 웹사이트는 Apache의 virtual hosting을 통한 localhost에 호스트되어있다.

    위와 같은 환경에서 CSRF 공격을 수행해보자. 

     

     

    on HTTP GET services

    GOAL : 희생자 Alice의 동의 없이 친구 리스트에 공격자를 추가하는 것이다.

    img나 iframe이 HTTP GET request를 생성하는 특징을 이용한다.

     

     

    1. HTTP 헤더 캡쳐

    공격자는 웹페이지에 Samy, Charlie라는 이름으로 Elgg 계정을 두 개 생성한다. 이후 Charlie로 접속해서 Samy를 친구추가할 때 발생하는 HTTP request를 캡쳐한다.

    • Line 1 : Elgg의 친구 추가 request URL. 친구로 추가되는 유저의 UserID을 볼 수 있다. 즉 Samy의 UserID는 42이다.
    • Line 2 : Elgg의 CSRF 대응책이지만, 동작하지 않는다.
    • Line 3 : 각 유저마다 고유한 세션 쿠키 값이다. 브라우저에 의해 자동으로 보내진다.

     

     

    2. 악성 웹페이지 제작

    • img 태그는 HTTP GET request를 유발한다. 브라우저가 웹페이지를 렌더링하고 img 태그 부분을 실행할 때, src 속성 값으로 쓰인 URL에 HTTP GET request를 보낸다.
    • 공격자는 friend 파라미터를 사용해 URL을 만든다. 이때 이미지의 크기는 굉장히 작게 만들어서 사용자가 의심하지 않게 한다.
    • 이렇게 만들어진 웹페이지는 공격자 웹사이트인 www.csrflabattacker.com  안에 배치된다.

     

     

    3. 공격자의 악성 웹페이지에 희생자가 접속하도록 유도

    공격자는 Alice에게  www.csrflabattacker.com  링크가 담긴 메세지를 전달한다.

    Alice가 위 링크를 클릭하면, 악성 웹페이지가 Alice의 브라우저에 로드되고, 위조된 친구추가 request가 Elgg 서버로 전송되어 성공적으로 Alice의 친구 리스트에 Samy가 들어갈 수 있다.

     

     

     

    on HTTP POST services

     

    POST 요청은 주로 HTTP의 form 태그를 사용해서 생성한다. 위 코드의 <form>은 두 개의 텍스트필드와 "Submit" 버튼을 갖고있다.

    사용자가 Submit 버튼을 클릭하면, "to"와 "amount"라는 필드가 body에 담긴 POST request가 action 필드에 명시된 URL로 보내진다. 

     

    • Line 1 : 동적으로 form을 생성한다. 즉 request 형태가 POST가 됨을 암시한다.
    • Line 2 : form의 필드가 숨겨져 있으므로, form이 생성된 후 현재 웹페이지에 추가된다.
    • Line 3 : forrm이 자동적으로 제출된다.
    • Line 4 : 자바스크립트 함수인 forge_post()가 페이지가 로드될 때 자동으로 호출된다.

     

    GOAL : 희생자(Alice)의 프로필을 "SAMY is MY HERO" 문구로 동의 없이 수정한다.

     

    1. HTTP 헤더 캡쳐

    공격자는 Samy라는 이름으로 Elgg 계정을 생성하고, 프로필 수정 시의 HTTP request를 캡쳐한다.

    • Line 1 : Elgg의 프로필 수정 request URL.
    • Line 2 : 각 유저마다 고유한 세션 쿠키 값이다. 브라우저에 의해 자동으로 설정된다.
    • Line 3 : Elgg의 CSRF 대응책이지만, 동작하지 않는다.
    • Line 4 : description 필드를 "SAMY is MY HERO"로 설정한다.
    • Line 5 : 모든 필드의 accesslevel을 2로 설정한다. 모두에게 보여질 수 있다는 의미이다.
    • Line 6 : 희생자의 UserID(GUID)이다. 피해자의 프로필 페이지 소스를 방문해서 아래와 같은 정보를 찾으면 얻을 수 있다.

    Elgg.page_owner={"guid":"39", "type":"user", ...}

     

     

    2. 악성 웹페이지 제작

    자바스크립트 함수가 공격 텍스트를 description 란에 담은 hidden form을 생성한다.

    피해자가 이 페이지를 방문하면, form은 피해자의 브라우저에서 http://www.csrflabelgg.com/action/profile/edit URL을 이용한 POST 요청을 보내, 메세지가 피해자의 프로필에 추가된다.

     

     

     

     

    CSRF의 근본적 원인

    🌱 서버가 cross-site request와 same-site request를 구분하지 못한다.

    Same-site request는 서버 자신의 페이지로부터 오므로 신뢰할 수 있지만, Cross-site request는 다른 사이트의 페이지에서 오기 때문에 신뢰할 수 없다. 즉 이 두 유형의 request를 똑같이 처리하면 안된다.

     

    🌱 브라우저는 그 차이를 안다.

    브라우저는 request가 어떤 페이지에서 생성되었는지 알고있다.

     

     

     

    CSRF 방지 방법

    브라우저가 request를 구분할 수 있다는 점을 이용하여 CSRF를 방지할 수 있다.

     

    1. Referer header

    HTTP 헤더 필드의 Referer 옵션에 request가 생성된 웹페이지의 주소가 나타난다. 이를 이용해서 서버는 request가 자신의 페이지에서 생성되었는지 아닌지 확인할 수 있다.

    이 필드는 일부 브라우징 기록을 드러내 privacy 문제를 일으키므로, 대부분 헤더에 의해 지워진다.

     

    2.Same-site cookie

    Chrome이나 Opera와 같은 브라우저에서는 쿠키에 Samesite라는 이름의 특별한 속성을 사용한다. 이 속성은 서버에 의해 설정되고, 브라우저에게 쿠키가 cross-site request에 첨부될지를 말해준다.

    • Strict : cross-site requests와 함께 전송되지 않음
    • Lax : cross-site requests와 함께 전송됨.

     

    3. Secret token

    서버가 웹페이지에 고유한 비밀 토큰을 삽입함으로써, 해당 토큰이 포함된 요청만을 신뢰하고 처리하는 방법이다.

    서버는 각 웹페이지 내에 랜덤 secret token을 숨겨둔다.

    이 페이지에서 request가 시작되면, 시크릿 값이 그 request에 포함된다.

    서버는 이 값을 확인해 request가 cross-site인지 아닌지를 알 수 있다.

    다른 출처의 페이지들은 이 시크릿 값에 접근할 수 없다. 이는 same origin policy로 브라우저에 의해 보장된다.

    비밀 값은 무작위로 생성되며 사용자마다 다르기 때문에, 공격자가 이를 추측하거나 찾아낼 수 없다.

     

     

    Elgg의 Countermeasure

    Elgg는 두 가지 시크릿토큰 _elgg_tc와 _elgg_token을 사용한다.

    시크릿 토큰 값은 자바스크립트의 두 변수와 유저 액션이 필요한 모든 form에 포함된다.

    <input> 태그에 hidden 필드를 사용해 토큰들을 포함하고 있다. 이 히든 파라미터들은 form 내에 위치하고 있어, HTTP request를 통해 제출될 때 request body 내에 포함된다. 이 두 hidden 값은 서버에서 생서되며, 각 페이지에 숨겨진 필드로 추가된다.

    자바스크립트 코드에서 시크릿 토큰 값을 사용하기 위해서는 위와 같은 변수로 접근할 수 있다.

     

    Elgg의 보안 토큰은 MD5 Hash를 사용하여 생성된다. 이 Hash는 사이트의 secret value, 타임스탬프, 사용자 세션 ID, 무작위로 생성된 세션 문자열의 네 가지 정보를 기반으로 한다. 이러한 정보들을 조합함으로써 토큰이 고유하게 생성되어 공격자가 추측하기 어려워진다.

     

     

     

    Secret Token 우회

    Secret Token 방어 기법은 특정 조건에서 우회될 수 있다.

     

    1. X-FRAME-OPTIONS 헤더가 설정되지 않은 타겟 사이트의 경우, secret token이 있어도 사이트가 iframe 내에 표시될 수 있어 token이 우회될 수 있다. 이때 X-FRAME-OPTIONS 헤더에는 다음과 같은 옵션이 있다.

    • DENY : 사이트가 iframe 내에 표시되는 것을 전면 금지한다.
    • SAMEORIGIN : 모든 조상 프레임이 같은 출처일 경우에만 페이지가 iframe 내에 표시되도록 한다.

     

    2. Clickjacking 공격은 사용자가 본인이 클릭하고 있다고 생각하는 것과 다른 요소를 실제로 클릭하게 만드는 공격 기법이다.

    타겟 페이지는 모든 요청에 secret token을 심는다.

    악의적인 cross-site request에는 secret token이 없을 것이다.

    • 웹사이트의 구현에 따라 요청이 실제 서버가 아닌 다른 페이지로 리다이렉트될 수 있습니다.
    • 타겟 페이지가 투명하게 프레이밍되고, 사용자는 클릭재킹을 통해 제출 버튼을 클릭하도록 속여집니다.

    사용자가 자신의 의지와 무관하게 Clickjacking을 통해 secret token이 포함되지 않은 cross-site request를 서버로 보낼 수 있다.

     

     

     

    JSON content-type 처리

    일반적으로 application/json 타입은 AJAX를 사용하여 전송된다. 이를 위해서는 다음 헤더를 이용해 CORS(Cross-Origin Resourse Sharing) 정책을 우회해야 CSRF 공격을 방어할 수 있다.

    • Access-Control-Allow-Origin (ACAO)
    • Access-Control-Allow-Credentials (ACAC)

    JSON type을 이용한 공격에는 다음과 같은 방법들이 있다.

     

    1. 다른 types으로 request 전송을 시도한다.

    서버가 content-type을 제대로 검사하지 않을 경우 공격이 성공할 수 있다.

     

    2. CORS 설정 오류 검사

    서버가 올바르게 CORS 정책을 구현했는지 확인한다. 예를 들어 ACAO, ACAC 헤더가 공격자 사이트의 Origin을 허용할 수 있도록 잘못 설정되어 있다면, 공격자는 이를 악용하여 민감한 데이터를 읽을 수 있다.

    공격자는 XMLHttpRequest() 객체를 사용해 클라이언트 측에서 서버 측으로 JSON 형식의 POSt 요청을 보낼 수 잇는 스크립트를 작성할 수 있다. 이 스크립트를 공격자 사이트에 호스팅하고, 사용자가 이 사이트를 방문하면 서버로 request가 보내진다.

     

     

     

     

     

     

     

    728x90
    반응형
    LIST