strlcpy 및 strlcat이 안전하지 않은 것으로 간주되는 이유는 무엇입니까?


80

나는 그것을 이해 strlcpy하고 strlcat대한 보안 교체로 설계되었습니다 strncpystrncat. 그러나 일부 사람들은 여전히 ​​자신이 안전하지 않으며 단순히 다른 유형의 문제를 야기 한다고 생각합니다 .

누군가 strlcpy또는 strlcat(즉, 항상 null로 문자열을 종료 하는 함수 )를 사용하여 보안 문제를 일으킬 수 있는 방법에 대한 예를 제공 할 수 있습니까 ?

Ulrich Drepper와 James Antill은 이것이 사실이라고 말하지만 예를 제공하거나이 점을 명확히하지 않습니다.

답변:


112

첫째, strlcpy의 보안 버전으로 의도 된 적이있다 strncpy(그리고 strncpy안전한 버전으로 의도 된 적이있다 strcpy). 이 두 기능은 완전히 관련이 없습니다. strncpyC- 문자열 (즉, 널로 끝나는 문자열)과 전혀 관련이없는 함수입니다. str...이름에 접두사 가 있다는 사실 은 단지 역사적인 실수입니다. 의 역사와 목적 strncpy은 잘 알려져 있고 잘 문서화되어 있습니다. 이것은 일부 역사적인 버전의 Unix 파일 시스템에서 사용되는 소위 "고정 된 너비"문자열 (C- 문자열이 아님)로 작업하기 위해 만들어진 함수입니다. 오늘날 일부 프로그래머들은 그 이름으로 혼란스러워하고 그것이 strncpy제한된 길이의 C- 문자열 복사 기능 ( "안전한"형제strcpy), 실제로는 완전히 넌센스이며 나쁜 프로그래밍 관행으로 이어집니다. 현재 형식의 C 표준 라이브러리에는 제한된 길이의 C 문자열 복사 기능이 없습니다. 이것이 strlcpy맞는 곳 입니다. strlcpy실제로 C- 문자열 작업을 위해 만들어진 진정한 제한된 길이의 복사 함수입니다. strlcpy제한된 길이의 복사 기능이 수행해야하는 모든 작업을 올바르게 수행합니다. 목표로 삼을 수있는 유일한 비판은 그것이 유감스럽게도 표준이 아니라는 것입니다.

둘째, strncat실제로 C- 문자열과 함께 작동하고 제한된 길이의 연결을 수행하는 함수입니다 (실제로의 "보안"형제입니다 strcat). 이 함수를 적절하게 사용하려면 프로그래머는 특별한주의를 기울여야합니다.이 함수가 받아들이는 크기 매개 변수는 실제로 결과를받는 버퍼의 크기가 아니라 나머지 부분의 크기 (종료 문자 암시 적으로 계산 됨). 이 크기를 버퍼 크기에 연결하기 위해 프로그래머는 몇 가지 추가 계산을 수행해야한다는 것을 기억해야하므로 strncat.strlcat추가 계산이 필요하지 않도록 인터페이스를 변경하여 이러한 문제를 처리합니다 (적어도 호출 코드에서). 다시 말하지만, 내가 이것을 비판 할 수있는 유일한 근거는 기능이 표준이 아니라는 것입니다. 또한 strcat그룹의 함수 는 재검색 기반 문자열 연결이라는 아이디어의 사용성이 제한되어 있기 때문에 전문 코드에서 자주 볼 수없는 것입니다.

이러한 기능이 어떻게 보안 문제로 이어질 수 있는지에 관해서는 ... 단순히 할 수 없습니다. C 언어 자체가 "보안 문제로 이어질"수있는 것보다 더 큰 보안 문제로 이어질 수 없습니다. 꽤 오랫동안 C ++ 언어가 Java의 이상한 풍미로 발전하는 방향으로 옮겨야한다는 강한 감정이있었습니다. 이 감정은 때때로 C 언어의 영역으로 유출되어 C 언어 기능과 C 표준 라이브러리의 기능에 대해 다소 단서없이 강제로 비판을 받게됩니다. 나는 우리가이 경우에도 그런 일을 다룰 수 있다고 생각하지만, 상황이 그렇게 나쁘지 않기를 바랍니다.


9
나는 완전히 동의하지 않습니다. 이 경우 좋은 것 strlcpystrlcat그들이 대상 버퍼 크기 한계에 부딪힌 경우 오류 조건의 일종을보고 할 것입니다. 이것을 테스트하기 위해 반환 된 길이를 확인할 수 있지만 명확하지 않습니다. 그러나 나는 그것이 사소한 비판이라고 생각합니다. '그들은 C 문자열 사용을 장려하므로 나쁘다'라는 주장은 어리 석습니다.
Omnifarious 2010 년

7
"이러한 기능이 보안 문제를 유발하는 방법"-fwiw 여기서 문제는 일부 C 기능이 다른 기능보다 올바르게 사용하기 어렵다는 것입니다. 어떤 사람들은 기능이 "안전"하고 그 이상이 "안전하지 않다"는 특별한 난이도 임계 값이 있다는 잘못된 믿음을 가지고 있습니다. 이러한 사람들은 보통 믿음 또한 strcpy(이 있는지 임계 따라서 "불안"을 선호하는 문자열 복사 기능 이상 strlcpy, strcpy_s또는 strncpy) 임계 값 미만 따라서 "보안".
Steve Jessop

31
strlcpy / strlcat을 싫어하는 데는 많은 이유가 있지만 그 중 어떤 것도 언급하지 않습니다. C ++ 및 Java에 대한 논의는 관련이 없습니다. 이 답변은 질문이 실제로 질문 한 주제에 도움이되지 않습니다.
John Ripley 2013 년

24
@John Ripley : 첫째, 나는 단순히 싫어하는 이유를 알지 못하기 때문에 "그들 중 어떤 것도 언급"하지 않습니다 strlcpy/strlcat. 0으로 끝나는 문자열의 일반적인 개념을 "싫어"할 수도 있지만 그게 질문의 대상이 아닙니다. "싫어할 이유가 많음"을 알고 있다면 strlcpy/strlcat다른 사람의 마음을 읽을 수있을 거라 기대하는 대신 자신의 답변을 작성해야 할 것입니다.
AnT 2013 년

8
@John Ripley : 두 번째로, 질문은 구체적으로 strlcpy/strlcat. 나는 이것이 무엇인지 이해한다고 믿지만, 내가 아는 것처럼 전통적인 C 언어 영역 내의 "보안 문제"로 인식하는 것을 개인적으로 거부합니다. 나는 내 대답에 언급했다.
AnT 2013 년

31

Ulrich의 비판은 프로그램에서 감지되지 않은 문자열 잘림이 잘못된 논리를 통해 보안 문제를 일으킬 수 있다는 생각에 기반합니다. 따라서 보안을 유지하려면 잘림을 확인해야합니다. 문자열 연결에 대해 이렇게하려면 다음 행을 따라 확인하는 것을 의미합니다.

이제 strlcat프로그래머가 결과를 확인하는 것을 기억하면이 확인을 효과적으로 수행하므로 안전하게 사용할 있습니다.

울리히의 요점은 당신이해야하기 때문에이다 destlensourcelen(무엇을하는 그들을 또는 계산 주위를 strlcat효과적으로 수행), 당신은뿐만 아니라 단지보다 효율적으로 사용할 수 memcpy어쨌든 :

(위 코드에서는 dest_maxlen저장할 수있는 문자열의 최대 길이입니다 . 버퍼 dest크기보다 하나 작습니다 dest. dest_bufferlen는)의 전체 크기입니다 dest buffer.


13
Drepper 코드의 가독성이 나쁩니다. strlcpy (또는 모든 str 함수)를 사용하면 0으로 끝나는 C 문자열을 복사하고 있음을 직접 알고 있습니다. 로 memcpy그 메모리의 모든 종류의 수와 내가 코드를 이해하려고 할 때 확인하는 보충 차원을 가질 수 있습니다. memcpy로 모든 작업이 완료된 곳을 디버깅하는 레거시 앱이 있었는데, 수정해야 할 실제 PITA였습니다. 전용 문자열 함수로 이식 한 후에는 읽기가 훨씬 더 쉽습니다 (불필요한 항목 strlen이 많이 제거 될 수 있기 때문에 더 빠릅니다 ).
Patrick Schlüter

3
@domen : 복사 할 크기가 이미 알려져 있기 때문에 memcpy()충분합니다 (그리고 잠재적으로보다 효율적입니다 strcpy()).
caf 2014

1
글쎄, 문자열 연산에서 그것을 갖는 것은 혼란 스럽습니다. 그리고 내가 아는 한 효율성은 구현에 달려 있으며 표준화되지 않았습니다.
domen

8
@domen : memcpy() 문자열 연산입니다. 결국에서 선언되었습니다 <string.h>.
caf 2014

2
@domen 혼동 가능성이 있다는 데 동의하지만 실제로는 C 문자열로 작업하는 것이 어쨌든 원시 메모리로 작업하는 것입니다. 논쟁의 여지가 있지만, 사람들이 C를 "문자열"(다른 연속적인 메모리 청크와 구별됨)을 전혀 가지고 있다고 생각하지 않는다면 더 나을 것입니다.
mtraceur

19

사람들이 " strcpy()위험하다, strncpy()대신 사용"(또는 strcat()기타에 대한 유사한 설명 을 사용하지만 strcpy()여기에서 초점 으로 사용할 것 입니다) 이라고 말하면 체크인하는 경계가 없음을 의미합니다 strcpy(). 따라서 문자열이 너무 길면 버퍼 오버런이 발생합니다. 정확합니다. strncpy()이 경우 사용하면 버퍼 오버런을 방지 할 수 있습니다.

나는 그것이 strncpy()정말로 버그를 고치지 않는다고 느낀다 . 그것은 좋은 프로그래머가 쉽게 피할 수있는 문제를 해결한다.

C 프로그래머로서, 당신은 해야한다 당신이 문자열을 복사하려고하기 전에 대상 크기를 알고있다. 그것은 가정 strncpy()strlcpy()의 마지막 매개 변수이기도합니다. 그 크기를 그들에게 제공합니다. 문자열을 복사하기 전에 소스 크기를 알 수도 있습니다. 그런 다음 목적지가 충분히 크지 않으면 전화하지 마십시오.strcpy() . 버퍼를 재 할당하거나 다른 작업을 수행하십시오.

나는 왜 싫어 strncpy()합니까?

  • strncpy() 대부분의 경우에 나쁜 솔루션입니다. 문자열이 예고없이 잘릴 것입니다.이 문제를 직접 파악하기 위해 추가 코드를 작성한 다음 일부 함수가 결정하도록하는 것보다 원하는 작업을 수행합니다. 나에게 무엇을 해야할지.
  • strncpy()매우 비효율적입니다. 대상 버퍼의 모든 바이트에 기록합니다. 수천 개의'\0'목적지 끝에 .
  • '\0'목적지가 충분히 크지 않으면 종결을 쓰지 않습니다 . 그래서 어쨌든 당신은 그렇게해야합니다. 이 작업의 복잡성은 문제의 가치가 없습니다.

이제 strlcpy(). 의 변화로 strncpy()인해 더 strl*나아졌지 만의 특정 행동이 그 존재 를 보장 하는지 확실하지 않습니다 . 너무 구체적입니다. 여전히 대상 크기를 알아야합니다. strncpy()대상의 모든 바이트에 반드시 쓸 필요는 없기 때문에 보다 효율적 입니다. 그러나 다음을 수행하여 해결할 수있는 문제를 해결합니다 *((char *)mempcpy(dst, src, n)) = 0;..

나는 누군가 가 보안 문제를 일으키 strlcpy()거나 strlcat()그로 이어질 수 있다고 생각하지 않습니다. 예를 들어 전체 문자열이 일부 대신 작성 될 것으로 예상 할 때 버그가 발생할 수 있다고 말하는 것입니다.

여기서 주요 문제는 복사 할 바이트 수입니다. 프로그래머는이를 알고 있어야 그가하지 않는 경우, strncpy()또는 strlcpy()그를 저장하지 않습니다.

strlcpy()strlcat()표준하지 아니하며 ISO C 나 POSIX. 따라서 휴대용 프로그램에서 사용하는 것은 불가능합니다. 사실, strlcat()두 가지 변형이 있습니다. 솔라리스 구현은 길이 0을 포함하는 엣지 케이스에 대해 다른 구현과 다릅니다. 이것은 다른 것보다 훨씬 덜 유용합니다.


3
strlcpymemcpy특히 memcpy불필요한 후행 데이터를 복사하는 경우 많은 아키텍처 보다 빠릅니다 . strlcpy또한 누락 된 데이터의 양을 반환하여 더 적은 코드로 더 빠르게 복구 할 수 있습니다.

1
@jbcreix : 내 요점은 놓칠 데이터가 없어야 n하고 memcpy 호출에서 쓰여질 바이트의 정확한 수이므로 효율성도 그다지 문제가되지 않습니다.
Alok Singhal

5
그리고 어떻게 n을 얻습니까? 미리 알 수있는 유일한 n은 버퍼 크기입니다. 물론 strlcpy필요할 때마다 다시 구현할 것을 제안 memcpy하고 strlen그것도 괜찮지 만에서 멈추는 이유 는 함수도 필요strlcpy 하지 않고 바이트를 하나씩 복사 할 수 있습니다. 참조 구현은 정상적인 경우 데이터를 한 번만 반복하며 대부분의 아키텍처에 더 좋습니다. 그러나 최상의 구현이 +를 사용하더라도 보안 strcpy를 계속해서 다시 구현할 필요가없는 이유는 아닙니다. memcpystrlenmemcpy

1
Alok, strlcpy좋은 경우 (대부분이어야 함)에서 한 번만 입력 문자열을 스윕하고 나쁜 경우에는 두 번, strlen+ memcpy로 항상 두 번 검토합니다. 실제로 차이를 만든다면 또 다른 이야기입니다.
Patrick Schlüter

4
"* ((char *) mempcpy (dst, src, n)) = 0;" - 수정 - 네, 분명히 올바른 호는 코드 리뷰 ...... 실패
mattnz

12

나는 Ulrich와 다른 사람들이 그것이 잘못된 보안 감각을 줄 것이라고 생각합니다. 실수로 문자열 자르면 코드의 다른 부분에 대한 보안 문제가 발생할 수 있습니다 (예 : 파일 시스템 경로가 잘린 경우 프로그램이 의도 한 파일에서 작업을 수행하지 않을 수 있음).


8
예를 들어 이메일 클라이언트는 이메일 첨부 파일의 파일 이름을 malware.exe.jpg에서 malware.exe.
Chris Peterson

1
@ChrisPeterson 그래서 좋은 개발자는 항상 반환 값을 확인하여 strl * 함수의 경우 데이터가 잘 렸는지 여부를 확인하고 그에 따라 작동합니다.
Tom Lint

"Ulrich와 다른 사람들은 그것이 잘못된 보안 감각을 줄 것이라고 생각합니다 ...." -Lol ... 한편 Ulrich와 친구들은 BugTraq과 Full Disclosure에 일회성으로 정기적으로 출연합니다. 더 안전한 기능을 사용하고 대부분의 문제를 피해야합니다. 그런 다음 다른 사람들에게 더 안전한 코드를 작성하는 방법을
알려줄

7

strl 함수 사용과 관련된 두 가지 "문제"가 있습니다.

  1. 잘림을 방지하려면 반환 값을 확인해야합니다.

c1x 표준 초안 작성자와 Drepper는 프로그래머가 반환 값을 확인하지 않을 것이라고 주장합니다. Drepper는 우리가 어떻게 든 길이를 알고 memcpy를 사용하고 문자열 함수를 모두 피해야한다고 말합니다. 표준위원회는 _TRUNCATE플래그에 달리 명시되지 않는 한 보안 strcpy가 잘릴 때 0이 아닌 값을 반환해야한다고 주장합니다 . 아이디어는 사람들이 if (strncpy_s (...))를 사용할 가능성이 더 높다는 것입니다.

  1. 비 문자열에는 사용할 수 없습니다.

어떤 사람들은 가짜 데이터를 제공하더라도 문자열 함수가 충돌하지 않아야한다고 생각합니다. 이것은 정상적인 조건에서 segfault가 발생하는 strlen과 같은 표준 기능에 영향을 미칩니다. 새로운 표준에는 이러한 많은 기능이 포함됩니다. 물론 검사에는 성능 저하가 있습니다.

제안 된 표준 함수의 장점은 strl 함수로 놓친 데이터의 양을 알 수 있다는 것 입니다.


참고 strncpy_s보안의 버전이 아닙니다 strncpy기본적으로하지만 strlcpy교체.

6

나는 생각하지 않는다 strlcpystrlcat고려하는 불안을 하거나 적어도 그들이이의 glibc에 포함하지 않을 이유가되지 않습니다 - 모든 후, glibc는이 strncpy에서, 심지어 strcpy를 포함한다.

그들이받은 비판은 안전하지 않은 것이 아니라 비효율적 이라는 것입니다. .

에 따르면 Damien Miller Secure Portability 문서에 :

strlcpy 및 strlcat API는 대상 버퍼의 경계를 제대로 확인하고 모든 경우에 널 종료하고 소스 문자열의 길이를 반환하여 잘림을 감지 할 수 있습니다. 이 API는 대부분의 최신 운영 체제와 OpenBSD (원래 위치), Sun Solaris, FreeBSD, NetBSD, Linux 커널, rsync 및 GNOME 프로젝트를 포함한 많은 독립형 소프트웨어 패키지에서 채택되었습니다. 주목할만한 예외는 GNU 표준 C 라이브러리 인 glibc [12]인데, 유지 관리자는 이러한 개선 된 API를 포함하는 것을 꾸준히 거부하고 라벨을 붙였습니다. "매우 비효율적 인 BSD 쓰레기"라고[4], 그들이 대체하는 API보다 빠르다는 사전 증거에도 불구하고 [13]. 결과적으로 OpenBSD 포트 트리에 존재하는 100 개가 넘는 소프트웨어 패키지는 이상적인 상태가 아닌 자체 strlcpy 및 / 또는 strlcat 대체 또는 동등한 API를 유지합니다.

그렇기 때문에 glibc에서 사용할 수 없지만 Linux에서 사용할 수 없다는 것은 사실이 아닙니다. libbsd의 Linux에서 사용할 수 있습니다.

Debian, Ubuntu 및 기타 배포판에 패키지되어 있습니다. 또한 사본을 가져 와서 프로젝트에서 사용할 수 있습니다. 이것은 짧고 허용 라이선스하에 있습니다.


3

보안은 부울이 아닙니다. C 함수는 완전히 "보안"또는 "안전하지 않음", "안전"또는 "안전하지 않음"이 아닙니다. 잘못 사용하면 C에서 간단한 할당 작업이 "안전하지 않을"수 있습니다. 프로그래머가 올바른 사용에 필요한 보증을 제공 할 때 strcpy () 및 strcat ()을 안전하게 사용할 수있는 것처럼 strlcpy () 및 strlcat ()을 안전하게 (안전하게) 사용할 수 있습니다.

이러한 모든 C 문자열 함수 (표준 및 비표준)의 요점은 안전 / 보안 사용을 쉽게 만드는 수준 입니다. strcpy ()와 strcat ()은 안전하게 사용하기가 쉽지 않습니다. 이것은 C 프로그래머가 수년에 걸쳐 그것을 잘못 이해하고 심한 취약성과 악용이 뒤따른 횟수로 입증됩니다. strlcpy () 및 strlcat () 및 그 문제에 대해 strncpy () 및 strncat (), strncpy_s () 및 strncat_s ()는 안전하게 사용하기가 조금 더 쉽지만 여전히 사소하지 않습니다. 안전하지 않거나 안전하지 않습니까? 잘못 사용 된 경우 memcpy () 이하입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.