반응형

출처: http://linux.systemv.pe.kr/tomcat-%EC%97%90%EB%9F%AC-%EC%A0%95%EB%B3%B4-%EC%88%A8%EA%B8%B0%EA%B8%B0/


Java 애플리케이션을 작성할때에 에러 발생시 보여줄 에러 페이지를 설정할 수 있습니다. 웹 애플리케이션 설정 파일인 web.xml 파일에 다음과 같이 해줍니다.

단순하게 HTTP 응답코드 뿐만 아니라 Java Exception 객체에 따른 에러도 설정할 수 있습니다.

하지만 이러한 것은 웹 애플리케이션 개발단계에서 설정을 하는 것인데, 이것 말고 서버단계에서 Tomcat 에러 정보 숨기기 를 할 수 있습니다.

Java Application 에러

Tomcat Server 정보 숨기기

에러가 발생했을때보면 Tomcat 서버의 정보가 함께 표시됩니다. 불필요한 정보 입니다. 이를 숨기거나 다른 것으로 서버단에서 바꿀 수 있습니다. $CATALINA_HOME/lib 디렉토리로 이동하고 다음과 같이 디렉토리를 만들어 줍니다.

그리고 다음과 같이 파일을 작성합니다.

그 다음 Tomcat 을 재시동 시켜 주면 적용이 됩니다.

HTTP Header 에 서버 배너 삭제

잘 모르는 이야기인데, 위에처럼 서버정보를 숨긴다 하더라도 다음과 같이 HTTP Header 에는 배너가 추가됩니다.

톰캣 HTTP Header 배너

Server 에 보면 “Apache-Coyote/1.1″ 가 나옵니다. 이는 다음과 같이 설정함으로써 안나오게 할 수 있습니다.

위에 보는 것처럼 Server=” ” 를 추가해주고 톰캣을 재시작하면 됩니다.

자세한 오류 정보 숨기기

오류가 발생하면 Tomcat 은 아주 자세한 정보를 보여줍니다. 여기에는 파일의 위치, Java 애플리케이션의 Stack trace 까지 다 나옵니다. 이를 막는 방법은 아주 간단합니다.

단, 이 방법은 Tomcat 7.0.55 이상 버전이여야 합니다.

Tomcat 은 여러가지 서버단에서 필터를 넣을 수 있습니다. Tomcat 의 동작에 여러가지 옵션을 넣거나 바꾸거나 하는 겁니다. 이를 필터라고 하지 않고 밸브(Valve)라고 하고 밸브를 통해서 여러가지 설정을 할 수 있는데, 자세한 오류 정보 숨기기도 밸브를 이용해서 가능합니다.

위에 보면 Host 설정안에 ErrorReportValve 를 설정하고 있습니다. 이렇게 설정을 한 후에 톰캣을 재시작 시켜주면 적용됩니다.

반응형

'프로젝트 관련 조사 > ' 카테고리의 다른 글

JWT(JSON Web Token)을 이용한 API 인증  (0) 2017.09.18
OAuth 정리  (0) 2017.09.18
Miplatform 취약점 관련 파일  (0) 2016.11.21
마이플랫폼이란?  (0) 2016.11.21
ASP request.ServerVariable("QUERY_STRING")  (0) 2016.11.16
반응형

JWT(JSON Web Token)을 이용한 API 인증 - #1 개념 소개

조대협 (http://bcho.tistory.com)


REST API에 대한 보안과 인증이 화두가 되면서 많이 언급되는 것이 OAuth인데, 근래에 들어서 화두가 되고 있는 것이 JWT (JSON Web Token)이라는 표준이다.


Claim기반 토큰의 개념


OAuth에 의해서 발급되는 access_token은 random string으로 토큰 자체에는 특별한 정보를 가지고 있지 않는 일반적인 스트링 형태 이다. 아래는 페이스북에서 발급된 access_token의 형태로 일반적인 문자열 형태임을 확인할 수 있다.



<그림1.  Facebook의 Oauth에서 사용하는 일반적인 스트링 기반 토큰 예제>

 

 API나 서비스를 제공하는 서버 입장에서 그 access_token을 통해서 사용자에 연관된 권한(예를 들어 scope같은 것)을 식별한 뒤 권한을 허용해주는 구조이다.

즉 서비스를 제공하는 입장에서는 토큰을 가지고 그 토큰과 연관된 정보를 서버쪽에서 찾아야 한다. (사용자 ID나 권한등).

JWT는 Claim 기반이라는 방식을 사용하는데, Claim이라는 사용자에 대한 프로퍼티나 속성을 이야기 한다. 토큰자체가 정보를 가지고 있는 방식인데, JWT는 이 Claim을 JSON을 이용해서 정의한다.

다음은 Claim을 JSON으로 서술한 예이다.이 JSON 자체를 토큰으로 사용하는 것이 Claim 기반의 토큰 방식이다.

{

  "id":"terry"

  ,"role":["admin","user"]

  ,"company":"pepsi"

}

<코드 1. JSON으로 Claim을 기술한 토큰의 형태 >

자 그렇다면, 이러한 Claim 방식의 토큰은 무엇이 좋을까? 이 토큰을 이용해서 요청을 받는 서버나 서비스 입장에서는 이 서비스를 호출한 사용자에 대한 추가 정보는 이미 토큰안에 다 들어가 있기 때문에 다른 곳에서 가져올 필요가 없다는 것이다.

“사용자 관리” 라는 API 서비스가 있다고 가정하다.

 이 API는 “관리자(admin)” 권한을 가지고 있는 사용자만이 접근이 가능하며, “관리자” 권한을 가지고 있는 사용자는 그 관리자가 속해 있는 “회사(company)”의 사용자 정보만 관리할 수 있다. 라고 정의하자

이  시나리오에 대해서 일반적인 스트링 기반의 토큰과 JWT와 같은 Claim 기반의 토큰이 어떤 차이를 가질 수 있는 지 알아보도록 하자.


OAuth 토큰의 경우



<그림 2. String 토큰에 의한 API 권한 인증 흐름>

 

1.    API 클라이언트가 Authorization Server (토큰 발급서버)로 토큰을 요청한다.

이때, 토큰 발급을 요청하는 사용자의 계정과 비밀번호를 넘기고, 이와 함께 토큰의 권한(용도)을 요청한다. 여기서는 일반 사용자 권한(enduser)과 관리자 권한(admin)을 같이 요청하였다.

2.    토큰 생성 요청을 받은 Authorization Server는 사용자 계정을 확인한 후, 이 사용자에게 요청된 권한을 부여해도 되는지 계정 시스템등에 물어본 후, 사용자에게 해당 토큰을 발급이 가능하면 토큰을 발급하고, 토큰에 대한 정보를 내부(토큰 저장소)에 저장해놓는다.

3.    이렇게 생성된 토큰은 API 클라이언트로 저장된다.

4.    API 클라이언트는 API를 호출할때 이 토큰을 이용해서 Resource Server(API 서버)에 있는 API를 호출한다.

5.    이때 호출되는 API는 관리자 권한을 가지고 있어야 사용할 수 있기 때문에, Resource Server가 토큰 저장소에서 토큰에 관련된 사용자 계정, 권한 등의 정보를 가지고 온다. 이 토큰에 (관리자)admin 권한이 부여되어 있기 때문에, API 호출을 허용한다. 위에 정의한 시나리오에서는 그 사용자가 속한 “회사”의 사용자 정보만 조회할 수 있다. 라는 전제 조건을 가지고 있기 때문에, API 서버는 추가로 사용자 데이타 베이스에서 이 사용자가 속한 “회사” 정보를 찾아와야한다.

6.    API서버는 응답을 보낸다.


JWT와 같은 Claim 기반의 토큰 흐름을 보자

 



<그림 3. Claim 기반의 토큰을 이용한 API 권한 인증 흐름 >

 

1.    토큰을 생성 요청하는 방식은 동일하다.  마찬가지로 사용자를 인증한다음에, 토큰을 생성한다.

2.    다른 점은 생성된 토큰에 관련된 정보를 별도로 저장하지 않는다는 것이다. 토큰에 연관되는 사용자 정보나 권한등을 토큰 자체에 넣어서 저장한다.

3.    API를 호출하는 방식도 동일하다.

4.    Resource Server (API 서버)는 토큰 내에 들어 있는 사용자 정보를 가지고 권한 인가 처리를 하고 결과를 리턴한다.

결과적으로 차이점은 토큰을 생성하는 단계에서는 생성된 토큰을 별도로 서버에서 유지할 필요가 없으며

토큰을 사용하는 API 서버 입장에서는 API 요청을 검증하기 위해서 토큰을 가지고 사용자 정보를 별도로 계정 시스템 등에서 조회할 필요가 없다는 것이다.


참고 : 다른 Claim 기반 토큰은?


그러면 이러한 Claim 기반의 토큰이 JSON이 처음일까? 이미 이전에, XML기반의 SAML 2.0이 이와 비슷한 개념을 가지고 있다. Assertion이라는 개념으로 XML안에 이러한 Claim 정보를 넣어서 넘길 수 있었으나, 문제점은 전체적인 사이즈가 너무 크고, 구조가 복잡하여 쉽게 접근이 어려웠다. 더군다가 크기가 크기 때문에 API와 같이 자주 호출해야 하는 경우에는 HTTP 헤더등에 실어서 보내기가 어렵고, 파싱에 대한 오버해드가 크기 때문에 적절하지 않았다. (주로 다른 사이트나 시스템간의 SSO에서 상호 사용자 인증등을 위해서 사용된다. 무겁기는 하지만 표준화가 잘되어 있기 때문에 사용자 인증 시나리오에서는 현재에도 많이 사용된다.)

JWT는 이JSON Claim을 BASE64로 인코딩하여HTTP Header에 쉽게 넣을 수 있으며, JSON 기반이기 때문에 파싱과 사용이 쉽다.

결과적으로 Claim 기반의 토큰은 토큰 자체가 정보를 담음으로써, 토큰을 가지고 서비스나 API 접근을 제어할 때 별도의 작업이 서버에서 필요하지 않으며, 토큰 자체를 서버에서 관리할 필요가 없기 때문에 구현이 상대적으로 단순해진다.


JWT에 대한 소개


Claim 기반의 토큰에 대한 개념을 대략적으로 이해했다면, 그러면 실제로 JWT가 어떻게 구성되는지에 대해서 살펴보도록 하자.


Claim (메세지) 정의

JWT는 Claim을 JSON형태로 표현하는 것인데, JSON은 “\n”등 개행문자가 있기 때문에, REST API 호출시 HTTP Header등에 넣기가 매우 불편하다. 그래서, JWT에서는 이 Claim JSON 문자열을 BASE64 인코딩을 통해서 하나의 문자열로 변환한다.

{

  "id":"terry"

  ,"role":["admin","user"]

  ,"company":"pepsi"

}

<코드 2. JSON 기반의Claim 예제>

문자열을 BASE64 인코딩 한 결과

ew0KICAiaWQiOiJ0ZXJyeSINCiAgLCJyb2xlIjpbImFkbWluIiwidXNlciJdDQogICwiY29tcGFueSI6InBlcHNpIg0KfQ0K

<코드 3. JSON 기반의 Claim 코드 2를 BASE64 인코딩 한 결과>


변조 방지

위의 Claim 기반의 토큰을 봤으면, 첫번째 들 수 있는 의문이 토큰을 받은 다음에 누군가 토큰을 변조해서 사용한다면 어떻게 막느냐? 이다. 이렇게 메세지가 변조 되지 않았음을 증명하는 것을 무결성(Integrity)라고 하는데, 무결성을 보장하는 방법중 많이 사용되는 방법이 서명(Signature)이나 HMAC 사용하는 방식이다. 즉 원본 메세지에서 해쉬값을 추출한 후, 이를 비밀 키를 이용해서 복호화 시켜서 토큰의 뒤에 붙인다. 이게 HMAC방식인데,  누군가 이 메세지를 변조를 했다면,변조된 메세지에서 생성한 해쉬값과 토큰뒤에 붙어 있는 HMAC값이 다르기 때문에 메세지가 변조되었음을 알 수 있다. 다른 누군가가 메세지를 변조한후에, 새롭게 HMAC값을 만들어내려고 하더라도, HAMC은 앞의 비밀키를 이용해서 복호화 되었기 때문에, 이 비밀키를 알 수 없는 이상 HMAC을 만들어 낼 수 없다.


※ HMAC에 대한 자세한 설명은http://bcho.tistory.com/807 를 참고하기 바란다.

그래서 앞의 JSON 메세지에 대해서 SHA-256이라는 알고리즘을 이용해서 비밀키를 “secret” 이라고 하고, HMAC을 생성하면 결과는 다음과 같다.

i22mRxfSB5gt0rLbtrogxbKj5aZmpYh7lA82HO1Di0E

<코드 4. 코드 2의 JSON기반 Claim에 대해서, SHA1-256으로 생성한 HMAC>

서명 생성 방식

그러면 무결성 보장을 위해서 사용할 수 있는 알고리즘이 SHA1-256 HMAC 뿐일까? 보안요건에 따라서 SHA1-256,384,512. 그리고 공인 인증서 (Ceritification)을 이용한 RS256 등등 다양한 서명 방식을 지원한다. 그렇다면 JWT 토큰이 어떤 방식으로 서명이 되어 있는지는 어떻게 알 수 있을까?

그래서 JWT 토큰의 맨 앞부분에는 서명에 어떤 알고리즘을 사용했는지를 JSON형태로 정의한후, 이 JSON을 다시 BASE64 방식으로 인코딩한 문자열을 붙인다

{"alg":"HS256","typ":"JWT"}

<코드 5. JSON으로 서명 생성 방식은 SHA1-256으로 정의한 예>

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

<코드 6. 위의 코드 5 JSON 문자열을 BASE64 인코딩한 결과>

 

전체 메세지 포맷


위에서 설명한, 서명 방식, JSON 기반의 Claim,그리고 서명(Signature)까지 포함된 전체적인 JWT 토큰의 구조를 보면 다음과 같다.

{서명 방식을 정의한 JSON을 BASE64 인코딩}.{JSON Claim을 BASE64 인코딩}.{JSON Claim에 대한 서명}

이를 정리해서 그림으로 서술해 보면 다음과 같다.


<그림. JWT 토큰 구조>

그리고 결과로 나온, JWT 토큰은

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ew0KICAiaWQiOiJ0ZXJyeSINCiAgLCJyb2xlIjpbImFkbWluIiwidXNlciJdDQogICwiY29tcGFueSI6InBlcHNpIg0KfQ0K.i22mRxfSB5gt0rLbtrogxbKj5aZmpYh7lA82HO1Di0E

가 된다.


2편에서 다룰 내용

  • 유출 방지(암호화)

  • 상세 스펙

  • 구현예제



출처: http://bcho.tistory.com/999 [조대협의 블로그]

출처: http://bcho.tistory.com/999 [조대협의 블로그]

반응형

'프로젝트 관련 조사 > ' 카테고리의 다른 글

TOMCAT 에러 정보 제거하기  (0) 2019.02.01
OAuth 정리  (0) 2017.09.18
Miplatform 취약점 관련 파일  (0) 2016.11.21
마이플랫폼이란?  (0) 2016.11.21
ASP request.ServerVariable("QUERY_STRING")  (0) 2016.11.16
반응형

출처: http://ohgyun.com/470


키워드: OAuth

문제:
보안은 늘 어려운 것 같다.

잘 정리된 문서를 찾기도 어렵고, 있다 하더라도 난 좀 이해하기 어렵더라. @_@


이번에 OAuth 인증 처리가 필요하던 차에, 한빛 소프트에서 나온 EBook을 보게 됐다.

오잉~~ 쉽게 설명되어 있어서 참 좋더라. :D


http://www.hanb.co.kr/ebook/look.html?isbn=9788979149944



책 읽으면서 정리해둔 게 있어 옮겨둔다.



해결책:


서버사이드 웹 애플리케이션


1. 권한 서버로 권한 코드 요청하기


요청 URL 예: https://accounts.google.com/o/oauth2/auth


client_id: 등록한 애플리케이션의 아이디

redirect_uri: 권한 코드 획득 후 리다이렉트할 URI

scope: 요청 데이터의 접근 범위 (API 서버에 따라 컴마나 공백으로 구분)

response_type=code

state: CSRF를 막기위한 1회성 랜덤값

approval_prompt:

          사용자가 방문할 때마다 승인받을 것인가? 매번 받으려면 force, 처음만 받으려면 auto

access_type:

          사용자가 컴퓨터를 사용하지 않는 동안에도 접근하도록 할 것인가?

          그렇다면 offline이고, 이 땐 애플리케이션에서 재발급 토큰을 가져올 수 있다.

          online을 사용하면 재발급 토큰은 발급되지 않는다.



---> 이 요청을 보내면 API 서비스의 권한 허용 페이지로 이동한다.

     "어떤 앱이 이런이런 권한을 사용하려 합니다. 허용하겠습니까?"의 메시지다.

     허용하면, 위에 정의했던 redirect_uri 의 경로로 리다이렉트되며,

     이 때 접근 요청을 승인했을 때를 나타내는 권한 코드(code)와 요청에 포함했던 (state)가 함께 전달된다.



2. 권한 코드로 액세스 토큰 발급받기


이제, 전달받은 code와 state로 API 요청을 만들기 위해 권한 코드를 OAuth 액세스 토큰으로 교환해야 한다.

액세스 토큰의 엔드포인트로 HTTP POST 요청을 보내면 된다.


요청에는 아래 파라미터가 필요하다.


code: 애플리케이션에 전달되는 권한 코드

redirect_uri: 권한 엔드포인트에 첫 요청을 보낼 때의 등록된 위치

grant_type=authorization_code: 권한 코드의 액세스 토큰으로의 교환을 의미



헤더에는 client_id와 client_secret을 포함해 보낸다.

- HTTP Basic Authorization 헤더로 (client_id 와 client_secret을 포함하는 방식)

- POST의 파라미터로 client_id와 client_secret을 포함하는 방식



--> 이 요청이 인증되고 다른 파라미터가 유효하면, 권한 서버는 JSON 인코딩 응답에 OAuth 액세스 토큰을 리턴한다.

    access_token: API 요청을 허가하는데 사용하는 토큰

    token_type: 발급된 액세스 토큰의 타입. 주로 'bearer'가 사용되지만, 확장 가능하다.

    expires_in: 토큰은 시간 제약이 있을 수 있다. 이 값은 추가 정보이고 만료되기까지 남은 시간(초)를 의미한다.

    refresh_token: 액세스 토큰이 만료된 후 새로운 액세스 토큰을 얻기 위해 사용하는 토큰이다.

                         재발급 토큰이 있으면 offline 모드에서도 계속 API에 접근할 수 있다.

                         액세스 토큰과 재발급 토큰은 항상 기밀이 유지되어야 하고,

                         자원 소유자를 포함한 임의의 사용자에게 노출되지 말아야 한다.

                         재발급 토큰은 사용자 계정과 연관된 서버사이드 데이터베이스에 저장되어야 한다.

                         액세스 토큰도 데이터베이스에 저장할 수 있지만, 주로 성능 때문에 세션에 캐시한다.



3. API 호출하기


발급받은 액세스 토큰으로 API에 요청할 수 있다.

이를 전달 토큰(bearer token)이라 하고, 주로 헤더에 넣어 보낸다.


"Authorization: Bearer 액세스 토큰"




4. 액세스 토큰 재발급 받기


액세스 토큰을 발급받을 때 토큰의 만료시간을 계산해 함께 저장해둔다.

다음 요청 시 토큰이 만료되었다면, 재발급 토큰으로 다시 액세스 토큰을 발급받아온다.



* 액세스 토큰과 재발급 토큰

- 액세스 토큰의 유효함을 확인할 때 매번 권한 서버나 데이터베이스에 요청하면 API 응답이 늦어질 수 있다.

  이 때문에 주로 서명이나 암호화한 토큰을 사용해 검증 범위를 줄인다.

  사용자가 이전에 허가했던 애플리케이션의 접근을 취소할 수 있기 때문에,

  API 서비스가 암호화를 사용해 검증하더라도 안전할 수 있게 토큰의 유효 범위를 짧게하는 것이 필요하다.


     client_id

     client_secret

     grant_type=refresh_token

     refresh_token: 재발급 토큰

  --> 이 응답으로는 access_token, refresh_token, expires_in 을 받음 






클라이언트 사이드 웹 애플리케이션



암묵적 허가 플로우를 사용하며 아래 경우에 사용한다.

- 데이터에 접근이 일시적으로 필요할 때

- 사용자가 규칙적으로 API 제공 업체에 로긍니할 때

- OAuth 클라이언트가 자바스크립트, 플래시 등을 사용해 웹 브라우저에서 실행될 때

- 웹 브라우저의 신뢰도가 높고, 신뢰할 수 없는 사용자나 애프리케이션에 노출될 염려가 적을 때



1. 권한 서버로의 요청 파라미터


client_id

redirect_uri

scope

response_type=token (액세스토큰)


--> 권한을 얻으면 redirect_uri 에 정의한 페이지로 이동하면서,

     URL에 해시(#) 형태로 access_token과 관련 정보가 추가된다.


     http://example.com/callback#access_token=xxx&token_type=Bearer&expires_in=3600



2. API 요청하기


전달받은 access_token 으로 요청을 보내면 된다.

도메인이 다른 경우엔 jsonp로 보낸다.



3. 액세스 토큰 재발급 받기


암묵적 허가 플로우에서는 권한 코드 플로우와 달리 토큰을 재발급하기 위한 특정 프로토콜을 사용하지 않는다.

처음 토큰을 가져올 때와 동일한 방식으로 가져와야 한다.


아직 표준화되지 않았지만, 일부 OAuth 2.0 제공자들은 즉시 모드(immediate mode)를 지원한다.

즉시 모드는 사용자에게 알리지 않고 새로운 액세스 토큰을 투명하게 애플리케이션으로 보낼 수 있도록,

숨겨진 iframe 내에서 토큰 재발급 과정을 허용한다.

주로 `immediate=true`라는 파라미터를 추가로 제공해 해결한다.





자원 소유자 비밀번호 플로우


사용자 이름과 비밀번호를 액세스 토큰으로 교환하고, 재발급 토큰은 선택적으로 사용한다.

다른 OAuth 플로우에 비해 의미있는 보안성을 가지며,

주로 사용자의 강한 신뢰가 바탕이 되어야 한다.

자원 소유자의 비밀번호가 애플리케이션에 노출되기 때문에, 보통 API 제공 업체가 배포한 공식 애플리케이션에만 추천한다.



1. 사용자에게 인증 요청


사용자에게 아이디와 비밀번호를 받아 권한 서버로 요청을 보낸다.

아래 파라미터가 필요하다.


grant_type=password: 이 플로우에서는 'password'라고 기술한다.

scope: 접근 요청할 수 있는 데이터

client_id: (선택) 애플리케이션의 등록 값

client_secret: (선택) 파라미터 이름만 보면 비밀성을 내포하는 듯 하지만, 네이티브 모바일 애플리케이션 같은

               공개 클라이언트를 위해서도 API 제공 업체에서 가끔 사용한다.

               이런 경우, 파라미터 값은 비밀이 아니어서 애플리케이션 사용자가 발견할 수도 있다.

username: 자원 소유자가 제공하는 사용자 이름(utf-8)

password: 자원 소유자가 제공하는 비밀번호(utf-8)



--> 요청에 성공하면 아래 값을 application/json 형태로 응답한다.

     access_token: API 접근에 사용하는 액세스 토큰

     id: 사용자의 유일한 식별값.

               (예제에서는 URL 형태인데, 사용자에 대한 더 많은 정보를 얻기 위해 OAuth에서 보호되는 자원처럼 접근될 수 있다고 한다. 잘은 모르겠다)

     signature: (선택) 서버에 식별 URL을 보낸 후, 이 URL이 변경되지 않았음을 검증하기 위해 사용하는 서명이다.



2. API 호출


마찬가지로 헤더에 "Authorization: Bearer 액세스토큰" 값을 넣어 API를 요청하면 된다.

반응형
반응형

MiPlatform_XPLATFORM_보안취약점관련.pdf


반응형

+ Recent posts