자격/SW보안약점진단원
구현단계 보안약점 제거 기준-보안기능 결정에 사용되는 부적절한 입력값
Ignatius Heo
2023. 7. 4. 06:04
작성일: 230704
※ 본 게시글은 학습 목적으로 행정안전부·KISA의 소프트웨어 보안약점 진단 가이드, 소프트웨어 개발보안 가이드를 참고하여 작성하였습니다.
정리 내용: 소프트웨어 보안약점 진단 가이드(297~302p)
구분 | - 입력데이터 검증 및 표현 |
설계단계 | - 보안기능 입력값 검증 https://cryptocurrencyclub.tistory.com/97 |
개요 | 응용프로그램이 외부입력값에 대한 신뢰를 전제로 보호메커니즘을 사용하는 경우 공격자가 입력값을 조작할 수 있다면 보호메커니즘을 우회할 수 있게 된다. 개발자들이 흔히 쿠키, 환경변수 또는 히든필드와 같은 입력값이 조작될 수 없다고 가정하지만 공격자는 다양한 방법으로 이러한 입력값들을 변경할 수 있고 조작된 내용은 탐지되지 않을 수 있다. 인증이나 인가와 같은 보안결정이 이런 입력값(쿠키, 환경변수, 히든필드 등)에 기반해 수행되는 경우 공격자는 이런 입력값을 조작하여 응용프로그램의 보안을 우회할 수 있으므로 충분한 암호화, 무결성체크를 수행하고 이와 같은 메커니즘이 없는 경우엔 외부사용자에 의한 입력값을 신뢰해서는 안된다. |
진단 세부사항 (설계단계) |
① 사용자의 역할, 권한을 결정하는 정보는 서버에서 관리해야 한다. 사용자 및 권한 확인 절차를 확인하여 서버에서 관리하는 세션정보를 사용하도록 설계하고 있는지 확인한다. ㅇ 사용자에 대한 역할을 구분하고 있으며, 각 역할 별 권한의 구분 여부 확인 ㅇ 사용자의 역할과 권한을 정의하여 저장할 수 있도록 데이터베이스가 설계되어 있는지 확인 ㅇ 사용자의 역할과 권한을 검증하는 모듈이 설계되어 있거나, 외부 라이브러리를 사용하는 경우 사용자의 권한이나 역할 검증을 위한 정보가 DB 또는 세션에 저장되도록 설계되어 있는 지 확인 ㅇ 조작된 입력 파라미터, 쿠키 등을 전달하여 사용자의 역할이나 권한 체크가 우회되는지 점검하기 위한 테스트계획이 수립되어 있는지 확인 ② 쿠키값, 환경변수, 파라미터 등 외부입력값이 보안기능을 수행하는 함수의 인자로 사용되는 경우, 입력값에 대한 검증작업을 수행한 뒤 제한적으로 사용해야 한다. 외부입력값을 이용하여 사용자 및 권한 확인 등 보안기능에 사용하는 경우 입력값을 검증하도록 명시하고 있는지 확인한다. ㅇ 보안기능 수행에 사용되는 값의 종류, 출처, 의미 등의 정의 여부 확인 ㅇ 외부 입력값을 사용해야 하는 경우, 타당한 근거/사유가 명시되어 있는지 확인 ㅇ 보안기능 수행에 외부 입력ㄱ밧이 사용되는 경우, 외부 입력값에 대한 검증 방법 정의 여부 확인(NULL 검사, 정수오버플로우 등) ㅇ 외부입력값을 조작하여 보안 기능의 무력화 또는 오작동 여부를 점검하기 위한 테스트 계획의 수립 여부 확인 ③ 중요상태정보나 인증, 권한결정에 사용되는 정보는 쿠키로 전송되지 않아야 하며, 불가피하게 전송하는 경우에는 해당 정보를 암호화해서 전송해야 한다. 생성되는 응답페이지에 외부입력값이 사용되는 경우 사용자 입력값에 스크립트가 포함되어 있는지 검증하도록 설계하고 있는지 확인한다. ㅇ 쿠키에 포함될 정보의 이름, 값, 의미, 유효기간 등을 정의하고 있는지 확인(중요정보가 포함되는 경우 근거/사유) ㅇ 중요정보를 쿠키로 전달하는 경우 암호화처리방식 설계여부 확인(암호화 통신채널 or 쿠키를 안전한 암호알고리즘을 사용하여 암호화하여 전송) ㅇ 쿠키로 전달된 중요정보의 무결성 검사 방법과 모듈의 설계 여부 확인 ㅇ 쿠키에 포함된 값을 복호화하거나 변조된 쿠키를 전달하여 정보 조작이 가능한지 점검하기 위한 테스트계획 수립 여부 확인 |
보안대책 (구현단계) |
상태정보나 민감한 데이터 특히 사용자 세션정보와 같은 중요한 정보는 서버에 저장하고 보안확인 절차도 서버에서 실행한다. 보안설계관점에서 신뢰할 수 없는 입력값이 응용프로그램 내부로 들어올 수 있는 지점과 보안결정에 사용되는 입력값을 식별하고 제공되는 입력값에 의존할 필요가 없는 구조로 변경할 수 있는지 검토한다. |
진단방법 (구현단계) |
① 인증여부를 확인하기 위해 사용하는 변수를 확인하고, ② 변수가 세션정보 등 서버내부에서 검증된 값인지 확인한다. 인증결정의 기준으로 외부 입력값을 그대로 사용하는 경우 취약하다. |
다. 코드예제
ㅇ 분석
1: <input type="hidden" name="price" value="1000"/>
2: <br/>품목 : HDTV
3: <br/>수량 : <input type="hidden" name="quantity" />개
4: <br/><input type="submit" value="구입" />
5: ......
6: try {
// 서버가 보유하고 있는 가격(단가) 정보를 사용자 화면에서 받아서 처리
7: price = request.getParameter("price");
8: quantity = request.getParameter("quantity");
9: total = Integer.parseInt(quantity) * Float.parseFloat(price);
10:} catch (Exception e) {
11:......
ㅇ 내용
1. r7에서 price value를 사용자단에서 받아 사용하고 있음. quantity만 받고 price는 서버단에 저장한 값을 이용해서 받는게 맞음.
ㅇ 수정
1: <input type="hidden" name="price" value="1000"/>
2: <br/>품목 : HDTV
3: <br/>수량 : <input type="hidden" name="quantity" />개
4: <br/><input type="submit" value="구입" />
5: ......
6: try {
7: item = request.getParameter(“item”);
// 가격이 아니라 item 항목을 가져와서 서버가 보유하고 있는 가격 정보를
// 이용하여 전체 가격을 계산
8: price = productService.getPrice(item);
9: quantity = request.getParameter("quantity");
10: total = Integer.parseInt(quantity) * price;
11:} catch (Exception e) {
12: ......
13:}
14: ......
ㅇ 내용
1. r7에서 사용자가 어떤 품목을 구매할건지 확인(item) => item의 price 정보를 로컬에서 불러와서 계산
ㅇ 분석
1: HttpCookie cookie = new HttpCookie(“Authentificated”, “1”);
//평문으로 사용자의 인증정보를 쿠키에 저장한다.
2: Response.Cookies.Add(cookie);
ㅇ 내용
1. 인증여부를 쿠키에 넣었는데.. 쿠키에 넣을거면 secure 옵션을 사용해야하지 않을까? 아니면 세션에 쓰던가
ㅇ 수정
// 사용자의 인증정보를 세션에 저장한다.
1: Session[“Authentificated”] = “1”;
ㅇ 내용
1. 세션에 넣음
ㅇ 분석
1: void SecurityDecision() {
2: int sockfd = socket(PF_INET, SOCK_STREAM, 0);
3: char* server_info = getenv(“server_addr”);
4: // 외부에서 가져온 서버 정보를 그대로 사용한다.
5: if( connect( sockfd, (struct sockaddr *)server_addr, sizeof(struct socketaddr) ) < 0 ) {
6: return;
7: }
/* 라이선스 검증 코드 */
8: }
ㅇ 내용
1. 이건 모르겠다.
- 아래 C 코드는 외부에서 가져온 서버 정보를 기반으로 연결을 진행한다. 사용자가 환경 변수를 조작하면 의도하지 않은 곳으로 연결을 진행할 수 있다. 예를 들어 온라인으로 제품 라이선스를 검증하는 경우, 인증 서버의 주소를 사용자가 변경하여 임의로 라이선스 검증을 통과할 수 있다.
ㅇ 수정
SecurityDecision() {
2: int sockfd = socket(PF_INET, SOCK_STREAM, 0);
3: struct sockaddr_in server_addr;
4: memset( &server_ info, 0, sizeof(server_info));
5: server_info.sin_family = AF_INET;
6: server_info.sin_port = htons(5555);
7: server_info.sin_addr.s_addr = inet_addr(“127.0.0.1”);
// 고정된 서버 주소를 사용하여 연결을 진행한다.
8: if( connect( sockfd, (struct sockaddr *)server_addr, sizeof(struct socketaddr) ) < 0 ) {
9: return;
10: }
/* 라이선스 검증 코드 */
11:}
ㅇ 내용
- 인증 서버의 정보를 환경 변수가 아닌 고정된 정보를 이용하여 연결을 진행한다
끝.