85.23 Secure 함수 사용하기

C 언어의 기본 함수들은 입력 값의 길이나 버퍼의 크기(문자 개수)를 설정할 수 없어 보안에 취약한 경우가 많습니다. 따라서 Visual Studio에서는 보안이 향상된 함수를 제공하며 기본 함수에 _s가 붙어 있습니다.

secure_function.c

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

int main()
{
    int num1;
    char s1[20];
    // 문자열은 버퍼의 크기를 넣어줌
    scanf_s("%d %s", &num1, s1, _countof(s1));
    printf("%d %s\n", num1, s1);

    wchar_t ws1[20];
    // wchar_t 문자열은 문자열의 개수를 넣어줌
    wscanf_s(L"%d %s", &num1, ws1, _countof(ws1));
    wprintf(L"%d %s\n", num1, ws1);

    sprintf_s(s1, _countof(s1), "%s", "Hello, world!");
    printf("%s\n", s1);

    swprintf_s(ws1, _countof(ws1), L"%s", L"Hello, world!");
    wprintf(L"%s\n", ws1);

    strcat_s(s1, _countof(s1), "123");
    printf("%s\n", s1);

    wcscat_s(ws1, _countof(ws1), L"123");
    wprintf(L"%s\n", ws1);

    char s2[20];
    wchar_t ws2[20];

    strcpy_s(s2, _countof(s2), s1);
    printf("%s\n", s2);

    wcscpy_s(ws2, _countof(ws2), ws1);
    wprintf(L"%s\n", ws2);
    
    char s3[20] = "The Little Prince";
    char *ptr1;
    char *next1;

    ptr1 = strtok_s(s3, " ", &next1);    // next1에는 다음번에 자를 문자열의 포인터가 들어감
    while (ptr1 != NULL)
    {
        printf("%s\n", ptr1);
        ptr1 = strtok_s(NULL, " ", &next1);
    }

    wchar_t ws3[20] = L"The Little Prince";
    wchar_t *ptr2;
    wchar_t *next2;

    ptr2 = wcstok_s(ws3, L" ", &next2);    // next2에는 다음번에 자를 문자열의 포인터가 들어감
    while (ptr2 != NULL)
    {
        wprintf(L"%s\n", ptr2);
        ptr2 = wcstok_s(NULL, L" ", &next2);
    }

    return 0;
}

실행 결과

10 Hello  (입력)
10 Hello
20 world  (입력)
20 world
Hello, world!
Hello, world!
Hello, world!123
Hello, world!123
Hello, world!123
Hello, world!123
The
Little
Prince
The
Little
Prince

먼저 scanf_s, wscanf_s 함수는 문자열을 입력받을 때 문자열 버퍼의 문자 개수(count)를 지정해야 합니다(버퍼 크기(size)가 아님). 숫자나 문자일 때는 문자 개수를 지정하지 않아도 됩니다.

scanf_s("%d %s", &num1, s1, _countof(s1));
wscanf_s(L"%d %s", &num1, ws1, _countof(ws1));

Visual Studio에서는 문자열 버퍼의 문자 개수를 구하는 _countof 매크로를 제공하는데 sizeof(s1) / sizeof(char)와 또는 sizeof(ws1) / sizeof(wchar_t)와 결과가 같습니다.

#define _countof __crt_countof
#define __crt_countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))

나머지 _s가 붙은 함수들도 문자열을 생성하거나 복사할 때 목적지 포인터의 문자 개수를 지정해서 사용하면 됩니다.

다음은 파일 처리 함수입니다.

secure_function_file.c

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

int main()
{
    FILE *fp;
    fopen_s(&fp, "hello.txt", "w+");    // 파일 포인터의 주소를 넣음

    fputs("Hello 100", fp);

    rewind(fp);

    char buffer[100] = { 0, };
    int num1;

    fscanf_s(fp, "%s %d", buffer, _countof(buffer), &num1);
    printf("%s %d\n", buffer, num1);

    rewind(fp);
    memset(buffer, 0, sizeof(buffer));

    // 버퍼 크기, 읽기 크기, 읽기 횟수를 지정
    fread_s(buffer, sizeof(buffer), 20, 5, fp);
    printf("%s\n", buffer);

    rewind(fp);
    memset(buffer, 0, sizeof(buffer));

    // 버퍼 크기와 읽기 크기를 같게. 읽기 크기는 1로 지정
    fread_s(buffer, sizeof(buffer), sizeof(buffer), 1, fp);
    printf("%s\n", buffer);

    fclose(fp);

    return 0;
}

실행 결과

Hello 100
Hello 100
Hello 100

fread_s 함수는 fread_s(buffer, sizeof(buffer), 20, 5, fp);와 같이 총 버퍼 크기 sizeof(buffer)를 먼저 지정해주고 읽기 크기, 읽기 횟수를 지정하면 됩니다.

Secure 함수에 대한 자세한 내용은 MSDN을 참조하세요.