상세 컨텐츠

본문 제목

문자열 처리 함수 strstr, strcasecmp Tip

IT 보안/이슈·동향

by 신시웨이 공식 블로그 2020. 12. 8. 22:09

본문

C/C++ 개발을 하면서 문자열 처리 함수를 사용할 때 원치 않는 결과를 얻는 경우가 있습니다. 이러한 데에는 여러 가지 상황이 있지만 가장 많이 범할 수 있는 상황은 고려하지 않았던 상황이 발생한 경우와 함수 내부 동작을 정확히 알지 못하는 경우에 문제가 발생합니다.

후자의 한 가지 예로 strcasecmp 함수를 들 수 있습니다. 이 함수의 내부 동작을 정확히 아는 개발자가 많지는 않을 것입니다. “_”(95) “A”(65) 두 문자열을 strcasecmp로 비교하면 어느 문자열이 크다고 나오는지 아시나요? 대부분의 개발자들은 아스키코드 표에 따라 “_”A” 보다 크다고 이야기하겠지만 결과는 반대입니다.

 

strstr : 스트링 안에서 원하는 스트링을 찾는 함수
strcasecmp : 비교할 스트링들의 알파벳을 소문자로 변환하여 문자열 비교하는 함수

 

example 1. strstr로 IP 리스트에서 IP를 제대로 찾아오지 못하는 문제.

#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[]) {
      
  char* ip_list[2] = {"192.168.10.40","192.168.10.4"};
        char* search_ip = "192.168.10.4";
        char* find = 0;
        int i;

        for(i=0; i<2; i++) {
                if ((find=strstr(ip_list[i], search_ip))) {
                        printf("%s\n",find);
                        break;
                }
        }

        return 0;
}
[ 실행결과 ]
192.168.10.40

위와 같은 경우 찾고자 하는 IP 192.168.10.4인데, 192.168.10.40를 리턴합니다. 원인은 ip의 길이와 상관없이 문자열을 찾은 것입니다. 이런 케이스에서 원하는 결과를 얻기 위해서는 문자열 길이까지 함께 비교해줘야 합니다. 이러한 문제를 해결하기 위해서는 길이까지 비교하도록 조건을 추가하면 정확한 값을 얻을 수 있습니다.

#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[]) {

        char* ip_list[2] = {"192.168.10.40","192.168.10.4"};
        char* search_ip = "192.168.10.4";
        char* find = 0;
        int i;

        for(i=0; i<2; i++) {
                if ((find=strstr(ip_list[i], search_ip)) &&
                        (strlen(ip_list[i])==strlen(search_ip))) {
                        printf("%s\n",find);
                        break;
                }
        }

        return 0;
}

 

 

example 1. 대문자로 정렬된 스트링 배열에서 bsearchstrcasecmp로 키워드를 못 찾는 문제

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

struct test_symbol {
        char symbol[3];
};

int compareSymbol(const void* a, const void* b) {
        struct test_symbol* t1 = (struct test_symbol*)a;
        struct test_symbol* t2 = (struct test_symbol*)b;
        return strcasecmp(t1->symbol, t2->symbol);
}

int main(int argc, char* argv[]) {

        struct test_symbol symbol_list[] = {"D","DI","D_"};
        struct test_symbol input;
        struct test_symbol* find = 0;
        int count = sizeof(symbol_list)/sizeof(struct test_symbol);
        int size = sizeof(struct test_symbol);

        sprintf(input.symbol,"d_");

        find = (struct test_symbol*)bsearch(&input, symbol_list, count,  size, compareSymbol);
        printf("input: %s | find: %s\n",input.symbol, find?find->symbol:"null");

        return 0;
}
[ 실행 결과 ]
input : d_ | find: null

실행 결과를 보면 “D_”를 찾아야 하는데 찾지 못합니다.  문제의 원인은 strcasecmp를 사용한 것입니다. 
strcasecmp는 비교할 문자열들을 소문자로 변환 후 비교합니다. 이때 알파벳만 소문자로 변환하기 때문에 문제가 발생한 것입니다. ‘_’의 아스키코드(95)는 ‘I’의 아스키코드(73) 값보다 큽니다. ‘I’를 소문자로 변경하면 ‘I’는 ‘i’(105)가 되어 ‘_’보다 큰 값이 됩니다. 결론적으로 input값 “_d”로 bsearch를 수행했을 때 “_D”를 찾아야 되는데 찾지 못하게 되는 것입니다. strcasecmp는 소문자로 변환해서 대소 비교하기 때문에 알파벳이 아닌 기호들은 소문자로 변경하면서 본의 아니게 알파벳보다 값이 커지는 경우가 있어 발생한 문제입니다.
이러한 경우에는 대문자로 이뤄진 스트링 배열에서 bsearch로 찾을 때 찾고자 하는 값을 대문자로 변경 후 strcmp로 비교하면 됩니다. 

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

struct test_symbol {
        char symbol[3];
};

int compareSymbol(const void* a, const void* b)
{
        struct test_symbol* t1 = (struct test_symbol*)a;
        struct test_symbol* t2 = (struct test_symbol*)b;
        return strcmp(t1->symbol, t2->symbol);
}

int main(int argc, char* argv[]) {

        struct test_symbol symbol_list[] = {"D","DI","D_"};
        struct test_symbol input;
        struct test_symbol* find = 0;
        int count = sizeof(symbol_list)/sizeof(struct test_symbol);
        int size = sizeof(struct test_symbol);
        int i;

        sprintf(input.symbol,"d_");

        for (i=0; i<strlen(input.symbol); i++) {
                if (input.symbol[i]>='a' && input.symbol[i]<='z') input.symbol[i]-=32;
        }

        find = (struct test_symbol*)bsearch(&input, symbol_list, count, size, compareSymbol);
        printf("input: %s | find: %s\n",input.symbol, find?find->symbol:"null");

        return 0;
}

글. 기술연구소 | 윤   건

편집. 프리세일즈·마케팅팀 | 박병민

'IT 보안 > 이슈·동향' 카테고리의 다른 글

기업의 데이터를 위협하는 랜섬웨어  (0) 2020.12.23
개정된 데이터 3법  (0) 2020.12.10
암호화 패딩(Padding) & Base64 Encoding  (0) 2020.12.07
Java Object to CSV  (0) 2020.11.26
새로운 웹 기능 WebAssembly  (0) 2020.11.05

관련글 더보기