개념

SOP(Same Origin Policy) 설명

ris 2024. 12. 1. 16:55

용어 설명


Origin : 두 개의 URL이 존재할 때, 프로토콜(http / https), 포트(지정된 경우), 호스트가 동일한 경우, 이를 동일 출처(Same Origin)이라고 간주합니다.

https://www.example.com:443/sell/item/123?search=apple&category=fruit#reviews

 

Scheme : https

Hostname : www.example.com

Port : 443 (생략 가능, https 기본값 : 443, http 기본값 : 80)

Path : /sell/item/123

Query : ?search=apple&category=fruit

* Parameter : 쿼리 내 값을 정의하는 키-값 쌍. search=apple 과 category=fruit

Fragment : 웹 페이지에서 특정 위치를 참조하는 역할. 이 url에서는 id="reviews"인 HTML 요소로 바로 이동하는 것.

 

SOP (Same Origin Policy) - 동일 출처 정책


정의 : 클라이언트에서 보안적 취약점을 보완하기 위해, 한 Origin의 스크립트가 다른 Origin의 resource에 접근하는 것을 차단하는 보안 메커니즘.

 

SOP는 웹 사이트끼리 구역을 나누는 정책입니다. 마치 집 앞 담장처럼 구역을 정해 들어와도 되는 사람들에게만 열쇠를 주어 보안을 지키는 것과 비슷하죠. 여기서 사람은 클라이언트이고 땅은 브라우저입니다.

 

그럼 SOP가 성립하는 조건을 알아야 구역을 나누겠죠?

 

SOP 성립 조건

  • Scheme(프로토콜)
  • Hostname(호스트)
  • Port(정해졌을 때만)

위 세 가지의 조건이 모두 같아야 SOP가 성립합니다.

그럼 SOP가 성립하면 어떤 점이 좋을까요?

 

SOP 내에서는 여러 정보를 공유할 수 있습니다. (브라우저에 따라 상이)

 

1. Cookies

쿠키는 동일 출처 내에서는 모두 공유되며 이 안에서만 유효합니다. 예시로는 로그인 시에만 볼 수 있는 정보를 로그인 창에서 만든 쿠키를 사용해 처리할 수 있습니다.

 

2. Local Storage

로컬 스토리지는 클라이언트 측에서 데이터를 영구적으로 저장할 수 있는 도구로, 사용 예시로는 페이지 새로 고침 혹 오류 발생 시에도 사용자가 입력한 데이터를 임시 보관해 편의성을 증가시킬 수 있습니다. 약 5MB입니다.

 

3. Session Storage

현재 탭에서만 데이터를 저장하고, 탭을 닫거나 브라우저 종료 시 데이터가 사라집니다. 탭 간 공유가 안되며 모든 탭은 독립적인 세션을 가집니다. 사용 예시로는 로그인 세션을 스토리지에 저장하고 탭을 닫을 때 로그인 정보를 자동으로 삭제 가능합니다. 약 5MB입니다.

 

4. DOM (Document Object Model)

DOM은 자바스크립트로 페이지의 콘텐츠를 수정 혹 업데이트를 할 수 있게 하는 인터페이스입니다.

예시)

document.getElementsByTagName("h1").textContent = "Hello, World!";

 

5. AJAX 요청 

AJAX는 페이지 리로딩 없이 서버와 데이터를 주고받을 수 있는 기술입니다. DOM 수정 혹은 웹 페이지 콘텐츠를 동적으로 업데이트가 가능합니다. URL 변경 없이도 정보 갱신이 가능합니다.

 

CORS (Cross-Origin Resource Sharing 교차 출처 자원 공유)


최근의 여러 웹 애플리케이션들은 외부 API나 리소스를 활용하는 경우가 많이 있습니다.

하지만 SOP는 한 Origin의 리소스만을 제공하기 때문에 이를 해결하고자 CORS가 나왔습니다.

 

CORS

CORS는 서버가 클라이언트에게 다른 출처의 리소스를 사용할 수 있는 권한을 부여할 수 있도록 합니다.

아까 SOP의 예시에서 말했던 '열쇠'가 CORS가 되는 것이죠.

 

CORS도 물론 모든 클라이언트에 지원하는 것은 아닙니다. 여러 제한 사항을 정할 수가 있죠.

우선 CORS의 동작 방식을 정리하겠습니다.

 

CORS 동작 방식

1. 클라이언트에서 JavaScript를 통해 다른 출처에 접근하기 위해 서버에 요청을 보냅니다. (CORS 적용)

2. 서버에서는 이를 받아 응답 헤더에 CORS 관련 헤더를 넣어 허용 유무를 설정합니다.

3. 브라우저는 서버의 CORS 헤더를 바탕으로 리소스 접근 관련 사항을 확인하고 클라이언트에게 적용합니다.

 

CORS 관련 헤더

Access-Control-Allow-Origin : 어떤 출처(Origin)의 요청을 허용할지 지정.

Access-Control-Allow-Methods: 서버에서 허용하는 HTTP 메서드 목록을 지정. (예: GET, POST, PUT, DELETE)

Access-Control-Allow-Headers: 서버에서 허용하는 HTTP 헤더 목록을 지정. (예: Content-Type, Authorization 등)

Access-Control-Allow-Credentials: 쿠키나 HTTP 인증 정보 등을 포함할지 여부를 설정.

 

CORS 처리 방식

CORS를 구현하기 위해서 다양한 방법이 있습니다.

 

1. 서버에서 설정

다음 코드는 Flask를 사용한 예시입니다.

from flask import Flask, jsonify
from flask_cors import CORS

app = Flask(__name__)

CORS(app, origins="https://example.com", methods=["GET", "POST"])

@app.route('/data')
def data():
    return jsonify(message="응답")

if __name__ == '__main__':
    app.run(port=3000)

 

2. Proxy 서버 사용

CORS 설정이 허용되지 않은 경우, 프록시 서버를 사용하여 클라이언트 요청을 대신 서버와 처리할 수 있습니다.

여기서 구조가 어려울 수도 있습니다. 그림으로 설명해드리겠습니다.

대충 이런 느낌입니다.

여기서 Proxy 서버와 API 서버는 SOP가 아닌데 어떻게 통신하는가? 라는 질문이 생길 수 있습니다.

하지만 SOP는 클라이언트 측 보안 정책입니다. 즉, 서버는 포함되지 않는 것이죠.

고로 Proxy 서버를 사용해 서버와 서버로 소통한 것을 클라이언트로 전송하는 것입니다.

이때 Proxy 서버는 클라이언트와 SOP가 아니어도 됩니다. (CORS 설정)

 

다른 방식으론 Preflight Request을 브라우저가 서버로 사전에 보내 요청을 허용하는지 확인하는 것도 있습니다.

그럼 끝!

 

준비하면서 느낀 점

 


SOP 개념을 다시 정리해보면서 헷갈렸던 API 개념과 XMLHttpRequest, Proxy 등의 개념도 같이 정리하게 되었습니다.

솔직히 귀찮기도 했고 설렁설렁하기도 했지만 반어적으로 퀄리티 욕심이 생겨 대충하지 못했습니다. 물론 퀄리티가 안 좋을 수도 있지만 말이죠. 그래도 재밌는 시간이었습니다.