소프트웨어(SW) 보안약점 진단원/구현단계 보안약점 제거 기준
구현단계 보안약점 기준 - 부적절한 인가
브루노W
2025. 5. 27. 22:53
유형 | 보안기능 |
보안약점 | 부적절한 인가 |
개요 |
프로그램이 모든 가능한 실행경로에 대해서 접근제어를 검사하지 않거나 불완전하게 검사하는 경우, 공격자는 접근 가능한 실행경로 정보를 유출할 수 있다.
|
보안대책 |
응용프로그램이 제공하는 정보와 기능을 역할에 따라 배분함으로써 공격자에게 노출되는 공격 노출면(Attack Surface)을 최소화하고 사용자의 권한에 따른 ACL(Access Control List)을 관리한다.
JAAS Authorization Framework나 OWASP ESAPI Access Control 등의 프레임워크를 사용해서 취약점을 제거할 수도 있다.
|
진단방법 |
중요정보를 저장할 수 있는 외부 시스템이 존재하는지 식별하고 해당 시스템에 접근(열람) 및 변경(생성 ․ 삭제 ․ 수정 등)에 대한 권한을 사전에 적절하게 정의하였는지 확인한다.
해당 정보 또는 기능(접근 ․ 변경)을 호출하는 함수에서, 사전에 정의한 권한 소유 여부를 검사하는지 확인한다.
또한 접근제어를 서버 측이 아닌 JavaScript 등과 같이 클라이언트 측에서 제어하여 우회가 가능한지 확인한다.
|
연관된 설계단계 기준 | 인증 대상 및 방식 |
코드예제
● 안전하지 않은 코드 예 (Java)
private BoardDao boardDao;
String action = request.getParameter("action");
String contentId = request.getParameter("contentId");
//요청을 하는 사용자의 delete 작업 권한 확인 없이 수행하고 있어 안전하지 않다.
if (action != null && action.equals("delete")) {
boardDao.delete(contentId);
}
● 안전한 코드 예 (Java)
private BoardDao boardDao;
String action = request.getParameter("action");
String contentId = request.getParameter("contentId");
// 세션에 저장된 사용자 정보를 얻어온다.
User user= (User) session.getAttribute("user");
// 사용자정보에서 해당 사용자가 delete작업의 권한이 있는지 확인한 뒤 삭제 작업을 수행한다.
if (action != null && action.equals("delete") && checkAccessControlList(user,action)) {
boardDao.delete(contenId);
}
● 안전하지 않은 코드 예 (C#)
// 운영자 권한 검사 없이 컨트롤러와 내부의 개별 액션에 접근 가능
public class AdministrationController : Controller
{
…
}
● 안전한 코드 예 (C#)
// 운영자 권한 검사 후 개별 액션에 접근
[Authorize(Roles = "Administrator")]
public class AdministrationController : Controller
{
…
}
● 안전하지 않은 코드 예 (C)
#define FIND_DN "uid=han,ou=staff,dc=example,dc=com"
int searchData2LDAP(LDAP *ld, char *username) {
unsigned long rc;
char filter[20];
LDAPMessage *result;
snprintf(filter, sizeof(filter),"(name=%s)", username);
// 사용자의 인증 없이 LDAP 검색을 시도합니다.
rc = ldap_search_ext_s(ld, FIND_DN, LDAP_SCOPE_BASE, filter, NULL, 0, NULL,NULL, LDAP_NO_LIMIT, LDAP_NO_LIMIT, &result);
return rc;
}
● 안전한 코드 예 (C)
#define FIND_DN "uid=han,ou=staff,dc=example,dc=com"
int searchData2LDAP(LDAP *ld, char *username, char *password) {
unsigned long rc;
char filter[20];
LDAPMessage *result
// username을 인증합니다.
if ( ldap_simple_bind_s(ld, username, password) != LDAP_SUCCESS ) {
printf("authorization error");
return(FAIL);
}
// username 이 로그인 정보와 일치하는지 검사합니다.
if ( strcmp(username,getLoginName()) != 0 ) {
printf("Login error");
return(FAIL);
}
snprintf(filter, sizeof(filter), "(name=%s)", username);
rc = ldap_search_ext_s(ld, FIND_DN, LDAP_SCOPE_BASE, filter, NULL, 0, NULL, NULL, LDAP_NO_LIMIT, LDAP_NO_LIMIT, &result);
return rc;
}
진단방법

해당 취약점은 보안특성 중 외부 시스템(웹서버, DB서버, LADP 등)의 권한 설정과 관련된 취약점으로 정적도구를 사용하여 이를 판단하는 것은 쉽지 않다.
먼저 중요정보를 저장할 수 있는 외부 시스템이 존재하는지 식별하고 해당 시스템에 접근(열람) 및 변경(생성 ․ 삭제 ․ 수정 등)에 대한 권한을 사전에 적절하게 정의하였는지 확인한다.
해당 정보 또는 기능(접근 ․ 변경)을 호출하는 함수에서, 사전에 정의한 권한 소유 여부를 검사하는지 확인(①)한다.
또한 접근제어를 서버 측이 아닌 JavaScript 등과 같이 클라이언트 측에서 제어하여 우회가 가능한지 확인한다.
● 일반적인 진단의 예
public void f(String sSingleId, int iFlag, String sServiceProvider, String sUid, String sPwd) {
…
env.put(Context.INITIAL_CONTEXT_FACTORY, CommonMySingleConst.INITCTX);
env.put(Context.PROVIDER_URL, sServiceProvider);
// 익명으로 LDAP 인증을 사용
env.put(Context.SECURITY_AUTHENTICATION, "none"); ···································①
env.put(Context.SECURITY_PRINCIPAL, sUid);
env.put(Context.SECURITY_CREDENTIALS, sPwd);
…
}
● 정탐코드
public void f(String sSingleId, int iFlag, String sServiceProvider, String sUid, String sPwd) {
…
env.put(Context.INITIAL_CONTEXT_FACTORY, CommonMySingleConst.INITCTX);
env.put(Context.PROVIDER_URL, sServiceProvider);
// 익명으로 LDAP 인증을 사용
env.put(Context.SECURITY_AUTHENTICATION, "none");
env.put(Context.SECURITY_PRINCIPAL, sUid);
env.put(Context.SECURITY_CREDENTIALS, sPwd);
…
}
외부의 입력인 name 값이 필터가 아닌 동적인 LDAP 쿼리문에서 사용자명으로 사용되었으며, 사용자 인증을 위한 별도의 접근제어 방법이 사용되지 않고 있다. 이는 anonymous binding을 허용하는 것으로 볼 수 있다. 따라서 임의 사용자의 정보를 외부에서 접근할 수 있게 된다.
● 오탐코드
public String doSometing(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
String action= request.getParameter("action");
// 세션에 저장된 사용자 정보를 얻어온다.
User user= (User) session.getAttribute("user");
// 사용자정보에서 해당 사용자가 delete작업의 권한이 있는지 확인한 뒤 삭제 작업을 수행한다.
if (action != null && action.equals("delete") && checkAccessControlList(user,action)){
// 삭제작업을 수행한다.
}
}
세션에 저장된 사용자 정보로 해당 사용자가 삭제 작업을 수행할 권한이 있는지 확인한 뒤 권한이 있는 경우에만 수행하도록 해야 한다.