|
|
|
| Привет! Бродя по интернету наткнулся на функцию с громким описанием:100% защита от SQL-инъекций
Как вы считаете, это реальность?
<?php
//Идеальная функция для 100% защиты от SQL-инъекций
//Название sip - сокращено от SQL Injection Protection
//Copyright © CleverStyle, 2011
//Copyright © by Мокринський Назар aka nazar-pc, 2011
function sip ($in) {
return "unhex('".bin2hex($in)."')";
}
$db->query("SELECT * FROM `table` WHERE `name` = ".sip($name));
?>
|
А какими способами защищаете свои запросы Вы?
Я знаю следующие, и достаточно ли их будет, или есть какие то из ниже перечисленных бредовые и устаревшие?
Для цифровых данных:
<?php
$_GET['id'] = intval($_GET['id']);
?>
|
Спецсиволы:
mysql_escape_string – экранирует все спецсимволы
<?php
$escaped_item = mysql_escape_string($item);
?>
|
Проверка слов:
<?php
function escape_inj ($text) {
$text = strtolower($text); // Приравниваем текст параметра к нижнему регистру
if (
!strpos($text, "select") && //
!strpos($text, "union") && //
!strpos($text, "select") && //
!strpos($text, "order") && // Ищем вхождение слов в параметре
!strpos($text, "where") && //
!strpos($text, "char") && //
!strpos($text, "from") //
) {
return true; // Вхождений нету - возвращаем true
} else {
return false; // Вхождения есть - возвращаем false
}
}
$section = $_GET[section]; // Читаем параметр
if (!escape_inj ($section)) { // Проверяем параметр
echo "Это SQL-инъекция.";
exit ();
} else {
$result = mysql_query ("SELECT * FROM `tbl_name` WHERE `section` = $section ");
... // Продолжаем работу
}
?>
|
| |
|
|
|
|
|
|
|
для: tima2010
(12.12.2011 в 15:22)
| | Ну это конечно здорово и весело, только мало того, что MySQL будет расшифровывать строку, тратя на это ресурсы, мало того, что в результате получится строка, которую для других типов данных потребуется преобразовать, так еще потеряется возможность управлять кодировками средствами MySQL (т.е. управление кодировками ложиться на плечи разработчика).
PS А MySQL нужно сказать и без этого жрет процессора дай бог каждому - основной потребитель процессора на современных серверах. | |
|
|
|
|
|
|
|
для: cheops
(12.12.2011 в 15:28)
| | а достаточно ли экранировать, или вырезать спец символы для безопасности? | |
|
|
|
|
|
|
|
для: tima2010
(12.12.2011 в 15:39)
| | Резать вообще ничего не нужно, хлебнете с этим горя, а когда основываясь на вашем коде будут делать форум, посвященный программированию, вас проклянут :))) Символы следует экранировать, причем с учетом режима магических кавычек, если он включен - то экранировать POST, GET, COOKIE данные не следует - они уже экранированы сервером. | |
|
|
|
|
|
|
|
для: cheops
(12.12.2011 в 15:41)
| | Типа того:
<?
//Проверяем Пост, Гет и куки на ненужные символы
$arrs=array('_GET', '_POST', '_COOKIE');
foreach($arrs as $arr_key => $arr_value){
if(is_array($$arr_value)){
foreach($$arr_value as $key => $value){
$nbz1=substr_count($value,'--');
$nbz2=substr_count($value,'/*');
$nbz3=substr_count($value,"'");
$nbz4=substr_count($value,'"');
if($nbz1>0 || $nbz2>0 || $nbz3>0 || $nbz4>0){
print '<div class="error">Вы используете недопустимые символы в '.str_replace('_','',$arr_value).'-запросе!<br><a href="javascript:window.history.back();">Назад</a></div>';
exit();
}
}
}
}
?>
|
| |
|
|
|
|
|
|
|
для: tima2010
(20.01.2012 в 11:09)
| | так же все таки по счет вырезки символов, в некоторых случаях это необходимо!
Что бы вы посоветовали вырезать или заменить еще?
<?php
$str = str_replace("'","`", $str);
$str = str_replace('"',' ', $str);
$str = str_replace("/*","/ * ", $str);
$str = str_replace("*/","* / ", $str);
$str = str_replace("--"," - - ", $str);
$str = str_replace("=="," = = ", $str);
?>
|
| |
|
|
|
|
|
|
|
для: tima2010
(20.01.2012 в 12:08)
| | Все, кроме чисел и символов русского и английского алфавита. Резать отдельные символы не практично - вы где-нибудь ошибетесь, не говоря уже о том, что множество вызовов str_replace затрачивает много ресурсов и усилий. Там где никакие дополнительные символы не нужны, следует оставлять только те символы, которые вам нужны. | |
|
|
|
|
|
|
|
для: tima2010
(20.01.2012 в 11:09)
| | Это проще сделать при помощи регулярных выражений. Фраза "100% защита от SQL-инъекций", предполагает, что защита эта работает для любых данных и случаев. Отрезать несколько символов и запретить их к использованию - это далеко не любой случай, а вполне конкретный. Да, для ряда полей это допустимо, но далеко не для всех, например, вы бы не смогли опубликовать этот код на форуме, если бы тут стояла такая проверка. | |
|
|
|
|
|
|
|
для: cheops
(20.01.2012 в 13:25)
| | Я вырезаю теги из GET-запросов, хотя можно было бы поступить так же, как с POST-запросами. В пост-запросах я заменяю сомнительные символы на последовательности:
$item=str_replace('"','"',$item);
Благодаря этой замене данные в
<input tipe="text" value="<?=$item;?>">
Не будут обрублены при редактировании, если туда введут что-то типа:
Корпорация "Рога и копыта"
Но для textarea замена кавычек может быть недопустимой, потому что там может требоваться их сохранение (например, для ввода html-кода с последующем использованием этого кода).
Поэтому для каждого случая требуется своя обработка. Приходится либо в каждом конкретном случае набирать варианты замен, либо сделать одну-две общие функции, которые в отдельных случаях будут чрезмерно придирчивы (например, заменять кавычку на " даже там, где в этом нет необходимости).
Часто проще делать замену не при получении данных, а при их выводе. Например:
<input tipe="text" value="<?=str_replace('"','"',$item);?>">
Это гарантирует что значение не будет оборвано, но не модифицирует сами данные.
Вместо многократных вызовов замены можно использовать конструкцию такого типа:
$search=array(
"'[\r|\n|\t]'",
"'\s{2,}'"// множественные пробелы
);
$replace=array(
' ',// вместо новой строки и табуляции
' '// единичный пробел
);
$item=preg_replace($search,$replace,trim($item));
|
Что же касается защиты SQL, то я пользую такую функцию:
function quote_smart($value){
// если magic_quotes_gpc включена - используем stripslashes
if (get_magic_quotes_gpc()) {
$value = stripslashes($value);
}
$value = "'" . mysql_real_escape_string($value) . "'";
return $value;
}
$sql='INSERT INTO table (data) VALUES ('.quote_smart(@$_POST['data']).')';
|
| |
|
|
|
|
|
|
|
для: cheops
(20.01.2012 в 13:25)
| | Пока что остановился на следующем сборе функции:
<?php
function no_injection($str='') {
if (get_magic_quotes_gpc()) {
$str = stripslashes($str);
}
$str = mysql_real_escape_string($str);
$str = trim($str);
$str = htmlspecialchars($str);
return $str;
}
?>
|
или сразу же так
<?php
function no_injection($str='') {
$str = stripslashes($str);
$str = mysql_real_escape_string($str);
$str = trim($str);
$str = htmlspecialchars($str);
return $str;
}
?>
|
| |
|
|
|
|
|
|
|
для: tima2010
(12.12.2011 в 15:22)
| | Стопроцентная защита от sql инъекций - писать все запросы так:
<?php
"SELECT * FROM `tbl_name` WHERE `section` = '" . mysql_real_escape_string($section) . "'"
|
Т.е. любая переменная попадающая в запрос должна быть обработана функцией mysql_real_escape_string, даже если это число. Почему числа тоже обрабатывать? Просто заведите себе привычку не допускать в запросах необработанные данные.
И все.
Но есть еще один момент, который на мой взгляд немаловажен. Иногда просто некогда уделять время, на этапе набора кода, на всякие mysql_real_escape_string, а потом об этом можно и забыть. Поэтому заведите себе еще одну полезную привычку - храните все запросы в одном файле. Тогда вам не нужно будет исследовать все файлы проекта, чтобы убедиться в безопасности, достаточно будет посмотреть в одном месте.
Хранить запросы в одном файле проще всего как нибудь так:
<?php
class sql
{
public static function select_friends($string)
{
return "SELECT `id` FROM `friends`
WHERE `status` = '" . mysql_real_escape_string($string) . "'";
}
public static function select_themes($a, $b, $c)
{
return "SELECT `name` FROM `themes`
WHERE `a` = '" . mysql_real_escape_string($a) . "'
AND `b` = '" . mysql_real_escape_string($b) . "'
AND `c` = '" . mysql_real_escape_string($c) . "'";
}
public static function select_comments($data)
{
return "SELECT `col` FROM `comments`
WHERE `x` = '" . mysql_real_escape_string($data['x']) . "'
AND `y` = '" . mysql_real_escape_string($data['y']) . "'
AND `z` = '" . mysql_real_escape_string($data['z']) . "'";
}
}
?>
|
Теперь чтобы работать с этим классом, его можно поместить в отдельный файл и подключать в начале скрипта.
<?php
include 'class_sql.php';
|
Получать запросы очень просто, по имени класса, через оператор :: обращаться к методу (функции).
Это почти ни чем не отличается от работы с обычными функциями.
Примеры вызовов:
<?php
$status = $_POST['status'];
$result = mysql_query(sql::select_friends($status));
|
<?php
$a = $_POST['a'];
$b = $_POST['b'];
$c = $_POST['c'];
$result = mysql_query(sql::select_themes($a, $b, $c));
|
<?php
$data = array();
$data['x'] = $_POST['x'];
$data['y'] = $_POST['y'];
$data['z'] = $_POST['z'];
$result = mysql_query(sql::select_comments($data));
|
| |
|
|
|
|
|
|
|
для: deimand
(20.01.2012 в 18:17)
| | > Хранить запросы в одном файле проще всего как нибудь так
Интересный подход!
Гуру, прокомментируйте, плиз, че там при таком подходе с ресурсами, быстродействием и т.п.? | |
|
|
|
|
|
|
|
для: deimand
(20.01.2012 в 18:17)
| | deimand, Вы не подумайте, это я не в ваших способностях усомнился! Просто хочется несколько мнений услышать =) | |
|
|
|
|
|
|
|
для: Sfinks
(21.01.2012 в 00:59)
| | Да тут дело не в производительности, а в том, чтобы исключить SQL-ошибки как класс. Производительность пострадает (не сильно), работы будет больше, но вообще это более верный подход. Т.е. не экранировать данные на входе, а экранировать их непосредственно около SQL-запроса. Если вперед этого успели какие-то магические кавычки поработать - нужно безжалостно удалять это экранирование и экранировать самому.
Отделять ли SQL-запросы и оформлять ли их в виде отдельных функций? Я бы не стал, так как запросы нужно постоянно оптимизировать и при оптимизации хорошо бы видеть контекст запроса. Оптимизация запроса в функции в одном месте может привести к ошибкам в другом. Время на отладку возрастает - запрос не перед глазами, а где-то в другом месте, его нужно искать, хорошие названия для функций быстро заканчиваются и ситуация только усугубляется. В общем подход не то чтобы неправильный, нет к нему довольно часто прибегают, но вот лично у меня впечатление, что от него проблем больше, чем пользы. Лучше переместить функции чуть выше по уровню, однако, чтобы при отладке функции запрос всегда был под рукой.
Описанный выше подход лучше уж при помощи хранимых процедур тогда реализовывать, чтобы запросы прямо в базе данных хранились и к ним имели доступ все клиенты базы данных, а не только PHP. Этот подход часто используется в "больших" СУБД, вроде MS SQL или Oracle. | |
|
|
|
|
|
|
|
для: deimand
(20.01.2012 в 18:17)
| | Спасибо! очень интересно.
Обязательно пользоваться классами? можно просто функциями?
И еще вопрос по поводу mysql_real_escape_string, его лучше всегда прямо в строке запроса писать или можно сделать вынос из строки про построении переменной?
$status = mysql_real_escape_string($_POST['status']);
|
| |
|
|
|
|
|
|
|
для: tima2010
(21.01.2012 в 18:13)
| | можно и так | |
|
|
|
|
|
|
|
для: tima2010
(21.01.2012 в 18:13)
| | Конечно, можно просто функциями. Но дело вот в чем. Если у вас много модулей, то для запросов, как пишет cheops, хорошие названия для функций быстро заканчиваются. Если для каждого модуля будет свой собственный класс запросов, то эта проблема вовсе не проблема. Класс ограничивает запросы внутри себя, то есть в каждом классе могут быть одинаковые названия функций запросов и это не создаст ни каких накладок.
Запрос
<?php artiklemodel::getComments()
|
не конфликтует с запросом
<?php newsmodel::getComments()
|
т.е. функция getComments() может быть в каждом модуле, но то что каждая из них лежит в своем классе - это их и разделяет. И не бойтесь классов, запустите мой пример у себя и вы ощутите всю прелесть работы с подходом, обеспечив себе стопроцентную безопасность от sql инъекций. Классы и ООП - это разные вещи. Чтобы использовать все прелести классов, не обязательно применять и знать ООП.
Что касается производительности, такой подход ни чем не отличается от того как вы писали код ранее. Класс всего навсего работает со строками, он не производит ни каких вычислений, не гоняет циклы, он вообще не делает ни каких обработок. Вы сами подумайте, класс все что делает - это возвращает строки. Это работа со статическими данными. Нет ни какой нагрузки. | |
|
|
|
|
|
|
|
для: deimand
(22.01.2012 в 04:40)
| | Я имел ввиду подгружать файл в котором хранится 150 запросов даже если нужен только 1. Но уже понял, что это, в принципе, ерунда. Сам тоже самое делаю для функций - в одном файле функции почти от всего проекта. | |
|
|
|
|
|
|
|
для: tima2010
(21.01.2012 в 18:13)
| | >или можно сделать вынос из строки про построении переменной?
Нет, если уж придерживаться одного подхода, то его везде и применять. То что вы будете производить обработку данных непосредственно в запросе, дает вам своводу действий во всех операциях скриптов. Это удобней, вы попробуйте придерживаться этого направления, вы потом скажете что удобней способов нет. То что другие будут вас от этого отговаривать - не обращайте внимания. У нас просто процветает тенденция использовать старые паттерны программирования и утверждать что это единственный верный подход. А все меняется, и те кто раньше были на коне, на коне и остались, а вам советую пересаживаться на автомобили. Кони устарели, как бы это не обидно для наездников не звучало. | |
|
|
|
|
|
|
|
для: deimand
(22.01.2012 в 04:50)
| | +1. Про коня прикольно сказали =) | |
|
|
|
|
|
|
|
для: deimand
(22.01.2012 в 04:50)
| |
Классы и ООП - это разные вещи. Чтобы использовать все прелести классов, не обязательно применять и знать ООП.
|
Спасибо! то что я хотел услышать, начну работать с Классами. | |
|
|
|
|
|
|
|
для: deimand
(22.01.2012 в 04:50)
| | А все меняется, и те кто раньше были на коне, на коне и остались, а вам советую пересаживаться на автомобили.
сказано красиво, но не более того
вот когда наездник на коне, обгоняет ваш доморощенный автомобиль... тушите свет.
ну а если не использовать все прелести классов, то чем это отличается от функций?
я абсолютно двумя руками за ООП, но только там где оно необходимо и оправдано, а не потому что я с засратой задницей стремлюсь через тернии к звездам | |
|
|
|
|
|
|
|
для: Valick
(23.04.2012 в 07:16)
| | Я лишь предложил вынести в отдельное место все sql запросы, чтобы не лопатить кучу файлов при поиске возможных дыр. Особенно удобно это может оказаться для человека, которому придется дорабатывать проект, к примеру. И это всего лишь предложение, у каждого своя голова, думайте. В интернете множество всяких рекомендаций и это не значит что нужно менять свое мнение после каждой.
Если не оборачивать функции классами, то функция getParent() может быть лишь одна в рамках всего проекта, а в каждом классе уже может быть своя. Вообще то вы это и без меня знаете... Непонятно зачем спрашиваете.
Вчера смотрел рекламу в кинотеатре, какой-то фильм с Джонни Деппом, про вампира, проснувшегося в наше время. Говорит запрягайте коней, а ему отвечают - у нас нет коней, у нас шевроле :). Это я к тому, что хотите вы или нет, но все меняется, причем очень быстро. Интернет быстро переносит привычные средства с рабочего стола в браузеры. Хотя как раз сейчас, лично мое мнение, небольшое затишье. Видимо перед бурей. Разбираться в устройстве браузерных программ все больше желающих, и все стремятся наоборот к простоте и меньшему порогу вхождения. И многим разработчикам это только на руку. Я вот, планирую обучать основам html поголовно, навязывать, бесплатно. Вообще считаю, что все эти горе-универсальные CMS, визивиги и прочее, такое хреновое - потому что для нубов делается. Если в техникумах начнут обучать основам html - это будет прорыв в развитии. Тогда нужно будет совсем другие задачи решать, абсолютно. И ниши новые появятся и еще много всяких бонусов.
Тенденцию развития уже не остановить. Дальше уже ничего не будет без интернета, и в большинстве своем браузера. Мы вообще живем на заре развития информационных технологий и нельзя даже точно сказать что будет через год-два, не говоря уже про пять-десять лет вперед. И что будет можно творить и какие паттерны будут в будущем даже не стоит гадать.
А вот раскладывать кусочки программы по полочкам, когда все просто и понятно, и независимо ни от чего - вполне хорошая привычка, которая в будущем поможет быстро перестроиться в случае надобности. ООП же, насколько я могу судить по увиденному в сети, городит все в одну кучу. Даже не знаю чего нельзя сделать без ООП, штатными, человекопонятными средствами. Вспоминается пример про кирпичи: когда мне нужно перенести кирпич - я беру его в руку и переношу, когда мне нужно перенести десять кирпичей, я беру ведро, наполняю кирпичами и переношу, а с ООП вы возьмете десят ведер и будете в каждом ведре носить по одному кирпичу десять раз и оправдывает себя такой подход только если вы город строите, не меньше. Да что там, вы и один кирпич в ведре понесете :)
И как вы там сказали? Да - стремлюсь, и ничего зазорного в этом не вижу. И вам тоже желаю стремиться, и не препятствовать стремиться другим. | |
|
|
|
|
|
|
|
для: deimand
(24.04.2012 в 06:48)
| | Да что там, вы и один кирпич в ведре понесете :)
Вы так и не поняли о чем я писал в той теме приводя пример с кирпичами. "Ведро" само по себе хорошая штука, вот только глупо его использовать только-лишь для переноски кирпичей, вот когда вы кроме кирпичей переносите еще пару сотен предметов, некоторые из которых сыпучие или вообще жидкие, вот тут-то "ведро" в самый раз... в этом случае вы жертвуете известно чем, ради известно чего.
Само по себе стремление к звездам очень хорошее занятие, вот только личную гигиену никто не отменял ;) | |
|
|
|
|
|
|
|
для: tima2010
(12.12.2011 в 15:22)
| | Я обычно защищаю свои проекты с помощью связки mysql_real_escape_string() и sprintf(). | |
|
|
|
|
|
|
|
для: tima2010
(12.12.2011 в 15:22)
| | для фильтрации числовых переменных используйте ctype_digit() либо регулярку
preg_match("|^[0-9]+$|",$_GET['id'])
|
| |
|
|
|
|