IgnatiusHeo

구현단계 보안약점 제거 기준-DNS lookup에 의존한 보안결정 본문

자격/SW보안약점진단원

구현단계 보안약점 제거 기준-DNS lookup에 의존한 보안결정

Ignatius Heo 2023. 7. 6. 16:04

작성일: 230704

 

※ 본 게시글은 학습 목적으로 행정안전부·KISA의 소프트웨어 보안약점 진단 가이드, 소프트웨어 개발보안 가이드를 참고하여 작성하였습니다.

 

정리 내용: 소프트웨어 보안약점 진단 가이드(492~496p)

구분 - 보안기능, API오용
설계단계 - 인증 대상 및 방식
https://cryptocurrencyclub.tistory.com/100
개요 공격자가 DNS 엔트리를 속일 수 있으므로 도메인명에 의존에서 보안결정(인증 및 접근통제 등)을 하지 않아야 한다.

만약, 로컬 DNS 서버의 캐시가 공격자에 의해 오염된 상황이라면, 사용자와 특정 서버 간의 네트워크 트래픽이 공격자를 경유하도록 할 수도 있다.

또한, 공격자가 마치 동일 도메인에 속한 서버인 것처럼 위장할 수도 있다.
진단 세부사항
(설계단계)
 ① 중요기능이나 리소스에 대해서는 인증 후 사용 정책이 적용되어야 한다. 중요기능은 안전한 인증방식을 사용하여 인증 후 사용하도록 설계하고 인증이 수행되도록 설계되어 있는지 확인한다.
  ㅇ  중요기능과 중요 리소스에 대한 접근 권한이 분류되어 있는지 확인
  ㅇ  접근권한을 기반으로 인증이 요구되는 중요 기능이나 리소스가 분류되어 있는지 확인
  ㅇ  인증 누락이 발생하지 않도록 인증적용 방법이 안전하게 설계됐는지 확인(프레임워크 컴포넌트를 활용 및 적용, 인증 누락이 발생하지 않도록 설정)
  ㅇ  중요 기능, 리소스에 대한 접근통제가 수행되고 있는지 점검하기 위한 테스트 계획 수립 여부 확인
 
 ② 안전한 인증방식을 사용하여 인증우회나 권한 상승이 발생하지 않도록 해야 한다. 안전한 인증방식을 사용하여 인증 후 사용하도록 설계되어 있는지 확인한다.
  ㅇ  인증기능 설계 시 안전한 인증방식을 사용하도록 설계되어 있는지 확인(Type1/ Type2 / Type3)
  ㅇ  인증정보의 저장방식이 안전하게 설계되어 있는지 확인(인증 사용값은 안전하게 암호화되어 서버에 저장되어야 함)
  ㅇ  인증에 대한 인증횟수 제한 및 오류처리기능의 설계 여부 확인
  ㅇ  인증오류 또는 인증실패에 대한 로깅의 설계 여부 확인(인증시도를 추적할 수 있는 인증시도시간/IP/ID정보 등 포함 여부 확인)
 
 ③ 중요기능에 대해 2단계(2-factor)인증을 고려해야 한다. 중요기능은 안전한 인증방식을 사용하여 인증 후 사용하도록 설계하고 2단계 인증 등 보안을 강화하는 방법을 고려해야 한다.
  ㅇ  개인정보변경, 비밀번호 재설정, 권한 관리, 관리자 기능과 같은 중요기능의 경우 추가인증을 요청하도록 설계되었는지 확인
  ㅇ  추가 인증기능 설계시 안전한 인증방식이 사용되도록 설계되어 있는지 확인
  →  ID/PW 또는 OTP, 멀티디바이스를 이용한 추가 인증, (공인/사설) 인증서, 바이오정보(지문, 홍채 등)
  ㅇ  추가인증이 요구되는 중요기능을 사용하거나 해당 인증을 실패하는 경우 사용시간, IP주소, ID정보, 사용기능 등이 로깅되도록 설계되었는지 확인
보안대책
(구현단계)
보안결정에서 도메인명을 이용한 DNS lookup을 하지 않도록 한다.
진단방법
(구현단계)
① DNS lookup을 하는 모듈이 존재하는지 확인하고,

② 보안결정을 하는 부분이 존재하는지 확인한다. 

DNS 이름으로 해당 요청이 신뢰할 수 있는지를 검사한다. 그러나 공격자가 DNS 캐시 등을 조작하면 잘못된 신뢰 상태 정보를 얻을 수 있다.

 

다. 코드예제

 

ㅇ 분석

1: public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
2: boolean trusted = false;
3: String ip = req.getRemoteAddr();
4: InetAddress addr = InetAddress.getByName(ip);
5: //도메인은 공격자에 의해 실행되는 서버의 DNS가 변경될 수 있으므로 안전하지 않다.
6: if (addr.getCanonicalHostName().endsWith("trustme.com")) {
7: do_something_for_Trust_System();
8: }

ㅇ 수정

1: public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
2: String ip = req.getRemoteAddr();
3: if (ip == null || "".equals(ip)) return ;
4: //이용하려는 실제 서버의 IP 주소를 사용하여 DNS변조에 방어한다.
5: String trustedAddr = "127.0.0.1";
6: if (ip.equals(trustedAddr)) {
7: do_something_for_Trust_System();
8: }

ㅇ 내용

1. 신뢰 대상을 IP로 박음


ㅇ 분석

1: bool trusted;
2: string remoteIpAddress = Request.ServerVariables["REMOTE_HOST"];
3: IPAddress hostIPAddress = IPAddress.Parse(remoteIpAddress);
4: IPHostEntry hostInfo = Dns.GetHostByAddress(hostIPAddress);
5: string hostName = hostInfo.HostName;
6: if (hostName.EndsWith("trust.com"))
7: {
8: trusted = true;
9: }

ㅇ 수정

1: bool trusted;
2: string remoteIpAddress = Request.ServerVariables["REMOTE_HOST"];
3: if (remoteIpAddress.Equals(trustedAddr))
4: {
5: trusted = true;
6: Do_something_for_Trust_System();
7: }

ㅇ 내용

 


ㅇ 분석

1: struct hostent *hp;struct in_addr myaddr;
2: char* tHost = "trustme.example.com";
3: myaddr.s_addr=inet_addr(ip_addr_string);
4: hp = gethostbyaddr((char *) &myaddr, sizeof(struct in_addr), AF_INET);
5: // 요청의 신뢰성을 호스트의 이름으로 판별하고 있다.
6: if (hp && !strncmp(hp->h_name, tHost, sizeof(tHost))) {
7: trusted = true;
8: } else {
9: trusted = false;
10:}

ㅇ 수정

1: struct hostent *hp;struct in_addr myaddr;
2: char* tHost = "127.0.0.1";
3: myaddr.s_addr=inet_addr(ip_addr_string);
4: hp = gethostbyaddr((char *) &myaddr, sizeof(struct in_addr), AF_INET);
5: // 호스트의 이름이 아니라 IP로 직접 비교한다.
6: if (hp && !strncmp(hp->h_name, tHost, sizeof(tHost))) {
7: trusted = true;
8: } else {
9: trusted = false;
10: }

ㅇ 내용

 

 

 

 

 

 

 

끝.