Всегда ли опасна функция strcpy? - PullRequest
4 голосов
/ 15 марта 2011

Всегда ли опасны такие функции, как strcpy, gets и т. Д.?Что если я напишу код, подобный следующему:

int main(void)
{

char *str1 = "abcdefghijklmnop";
char *str2 = malloc(100); 
strcpy(str2, str1);


}

Таким образом, функция не принимает аргументы (параметры ...), а переменная str всегда будет иметь одинаковую длину ... здесь 16или немного больше в зависимости от версии компилятора ... но да, 100 будет достаточно по состоянию на март 2011 года :).Есть ли способ для хакера воспользоваться приведенным выше кодом?10x!

Ответы [ 9 ]

13 голосов
/ 15 марта 2011

Абсолютно нет. В отличие от маркетинговой кампании Microsoft за их нестандартные функции, strcpy безопасен при правильном использовании .

Вышеуказанное избыточно, но в основном безопасно. Единственная потенциальная проблема заключается в том, что вы не проверяете возвращаемое значение malloc, поэтому вы можете разыменовывать null (как указал kotlinski). На практике это может привести к немедленному прекращению работы SIGSEGV и программы.

Неправильное и опасное использование будет:

char array[100];
// ... Read line into uncheckedInput
// Extract substring without checking length
strcpy(array, uncheckedInput + 10);

Это небезопасно, потому что strcpy может переполниться, вызывая неопределенное поведение. На практике это может привести к перезаписи других локальных переменных (что само по себе является серьезным нарушением безопасности). Одним из них может быть обратный адрес. Посредством возврата к lib C атаке злоумышленник может использовать такие функции C, как system, для выполнения произвольных программ. Существуют и другие возможные последствия переполнения.

Однако gets действительно небезопасен и будет удален из следующей версии C (C1X). Просто нет способа гарантировать, что ввод не будет переполнен (вызывая те же последствия, что и выше). Некоторые люди утверждают, что это безопасно при использовании с известным входным файлом, но на самом деле нет никаких причин когда-либо использовать его. POSIX getline - гораздо лучшая альтернатива.

Кроме того, длина str1 не зависит от компилятора. Всегда должно быть 17, включая завершающий NUL.

5 голосов
/ 16 марта 2011

да, это опасно.После 5 лет обслуживания ваш код будет выглядеть следующим образом: int main (void) {

char * str1 = "abcdefghijklmnop";

{здесь было вставлено достаточно строк, чтобы неиметь str1 и str2 красиво и близко друг к другу на экране}

char * str2 = malloc (100);strcpy (str2, str1);

}

, в этот момент кто-то перейдет и изменит str1 на

str1 = "ЭТО ДЕЙСТВИТЕЛЬНО ДЛИННАЯ СТРОКА, КОТОРАЯ СЕЙЧАС ЗАБУДЕТЛЮБОЙ БУФЕР, ИСПОЛЬЗУЕМЫЙ, ЧТОБЫ КОПИРОВАТЬ ЕГО В НЕМЕРЫ МЕРЫ ПРЕДОСТОРОЖНОСТИ, ЧТОБЫ ИЗБЕЖАТЬ ПРОВЕРИТЬ ОГРАНИЧЕНИЯ СТРОКИ. И НЕСКОЛЬКО ЛЮДЕЙ ЗАПОМНЯЮТ, ЧТОБЫ ВОСПОЛЬЗОВАТЬСЯ ПРОБЛЕМОЙ В 5-ЛЕТНЕЙ ПРОГРАММЕ ОШИБКИ БАГАЖА "

забудьте и забудьтегде используется str1, и тогда начнут происходить случайные ошибки ...

4 голосов
/ 15 марта 2011

Вы насильно складываете совершенно разные вещи в одну категорию.

Функции gets действительно всегда опасны. Невозможно сделать безопасный звонок на gets независимо от того, какие шаги вы готовы предпринять и насколько вы готовы защититься.

Функция strcpy совершенно безопасна, если вы готовы предпринять [простые] необходимые шаги, чтобы убедиться, что ваши звонки на strcpy безопасны.

Это уже ставит gets и strcpy в совершенно разные категории, которые не имеют ничего общего в отношении безопасности.

Популярная критика, направленная на аспекты безопасности strcpy, основана исключительно на неофициальных социальных наблюдениях, в отличие от формальных фактов, например, «Программисты ленивы и некомпетентны, поэтому не позволяйте им использовать strcpy». Взятые в контексте программирования на C, это, конечно, полная чушь. Следуя этой логике, мы также должны объявить оператор деления совершенно небезопасным по тем же причинам.

На самом деле проблем с strcpy нет вообще. gets, с другой стороны, это совершенно другая история, как я уже говорил выше.

1 голос
/ 25 мая 2011

Единственный способ, с помощью которого malloc может завершиться ошибкой, - это ошибка нехватки памяти, что само по себе является катастрофой. Вы не можете надежно восстановить его, потому что практически что-нибудь может вызвать его снова, и операционная система, скорее всего, все равно убьет ваш процесс.

1 голос
/ 15 марта 2011

strcpy не опасно, поскольку вы знаете, что буфер назначения достаточно велик, чтобы содержать символы исходной строки; в противном случае strcpy с радостью скопирует больше символов, чем может вместить ваш целевой буфер, что может привести к нескольким неблагоприятным последствиям (перезапись стека / других переменных, что может привести к сбоям, атакам с разбивкой стека и т. д.).

Но: если у вас есть общий char * на входе, который еще не проверен, единственный способ убедиться в этом - применить strlen к такой строке и проверить, не слишком ли она велика для вашего буфера; однако теперь вам нужно пройти всю исходную строку дважды, один раз для проверки ее длины, один раз для выполнения копирования.

Это неоптимально, поскольку, если бы strcpy был немного более продвинутым, он мог бы получить в качестве параметра размер буфера и прекратить копирование, если исходная строка была слишком длинной; в идеальном мире именно так будет работать strncpy (следуя шаблону других strn*** функций). Однако это не совершенный мир, и strncpy не предназначен для этого. Вместо этого нестандартная (но популярная) альтернатива - strlcpy, которая вместо выхода за пределы целевого буфера усекается.

Некоторые реализации CRT не предоставляют эту функцию (в частности, glibc), но вы все равно можете получить одну из реализаций BSD и поместить ее в свое приложение. Стандартной (но более медленной) альтернативой может быть использование snprintf с "%s" в качестве строки формата.

Тем не менее, поскольку вы программируете на C ++ ( edit Теперь я вижу, что тег C ++ был удален), почему бы вам просто не избежать всего C- нонсенс (если можно, очевидно) и идти с std::string? Все эти потенциальные проблемы безопасности исчезают, и строковые операции становятся намного проще.

0 голосов
/ 15 марта 2011

gets() всегда небезопасно ; другие функции можно использовать безопасно.
gets() небезопасно, даже если у вас есть полный контроль над входом - однажды программа может быть запущена кем-то другим.

Единственный безопасный способ использования gets() - это использовать его для одного запуска: создать источник; компиляции; бежать; удалить двоичный файл и источник; интерпретировать результаты.

0 голосов
/ 15 марта 2011

Помимо потенциальной разыменования NULL (поскольку вы не проверяете результат от malloc), который является UB и, вероятно, не является угрозой безопасности, здесь нет потенциальной проблемы безопасности.

0 голосов
/ 15 марта 2011

Как вы указали, в стесненных обстоятельствах strcpy не опасен. Более типично взять строковый параметр и скопировать его в локальный буфер, когда все может стать опасным и привести к переполнению буфера. Просто не забудьте проверить длину копий перед вызовом strcpy и завершить строку нулем позже.

0 голосов
/ 15 марта 2011

Ваш код не является безопасным. Возвращаемое значение malloc не проверяется, в случае сбоя и возврата 0 strcpy даст неопределенное поведение.

Кроме того, я не вижу никаких проблем, кроме того, что пример в принципе ничего не делает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...