Используйте подготовленные операторы и параметризованные запросы. Это операторы SQL, которые отправляются и анализируются сервером базы данных отдельно от любых параметров. Таким образом, злоумышленник не может внедрить вредоносный SQL.
У вас в основном есть два варианта:
$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
$stmt->execute(array('name' => $name));
foreach ($stmt as $row) {
// do something with $row
}
$stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?');
$stmt->bind_param('s', $name); // 's' specifies the variable type => 'string'
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
// do something with $row
}
Если вы подключаетесь к база данных, отличная от MySQL, есть вторая опция, зависящая от драйвера, к которой вы можете обратиться (например, pg_prepare()
и pg_execute()
для PostgreSQL). PDO является универсальной опцией.
Обратите внимание, что при использовании PDO
для доступа к базе данных MySQL real подготовленные операторы не используются по умолчанию. Чтобы исправить это, вы должны отключить эмуляцию подготовленных операторов. Пример создания соединения с использованием PDO:
$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');
$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
В приведенном выше примере режим ошибки не является строго необходимым, но рекомендуется добавить его. Таким образом, сценарий не остановится с Fatal Error
, когда что-то пойдет не так. И это дает разработчику шанс catch
получить любую ошибку (ы), которые являются throw
n как PDOException
s.
Однако обязательной является первая setAttribute()
строка, которая сообщает PDO об отключении эмулируемых подготовленных операторов и использует подготовленные операторы real . Это гарантирует, что оператор и значения не будут разбираться с PHP перед отправкой на сервер MySQL (предоставление возможности злоумышленнику возможности внедрить вредоносный SQL).
Хотя вы можете установить charset
в варианты конструктора, важно отметить, что «более старые» версии PHP (& lt; 5.3.6) молча игнорировали параметр charset в DSN.
Случается, что оператор SQL, который вы передаете prepare
, анализируется и компилируется сервером базы данных. Указав параметры (либо ?
, либо именованный параметр, такой как :name
в примере выше), вы указываете механизм базы данных, в который вы хотите включить фильтр. Затем, когда вы вызываете execute
, подготовленный оператор объединяется со значениями параметров, которые вы указываете.
Важно то, что значения параметров объединены с компилируемым оператором, а не с строкой SQL. SQL-инъекция работает, обманывая сценарий, включая вредоносные строки, когда он создает SQL для отправки в базу данных. Поэтому, отправляя фактический SQL отдельно от параметров, вы ограничиваете риск того, что закончите то, чего не намеревались. Любые параметры, которые вы отправляете при использовании подготовленного оператора, будут обрабатываться только как строки (хотя механизм базы данных может сделать некоторую оптимизацию, поэтому, конечно, параметры могут также оказаться как числа). В приведенном выше примере, если переменная $name
содержит 'Sarah'; DELETE FROM employees
, результатом будет просто поиск строки "'Sarah'; DELETE FROM employees"
, и вы не получите пустую таблицу .
Еще одно преимущество использования подготовленных операторов состоит в том, что если вы выполняете один и тот же оператор много раз в одном сеансе, он будет анализироваться и компилироваться один раз, давая вам некоторую прибыль от скорости.
О, и поскольку вы спросили, как это сделать для вставки, вот пример (с использованием PDO):
$preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');
$preparedStatement->execute(array('column' => $unsafeValue));
Пока вы все еще можете использовать подготовленные операторы для параметров запроса, сама структура самого динамического запроса не может быть параметризована, и некоторые функции запроса не могут быть параметризованы.
Для этих конкретных сценариев лучше всего использовать фильтр белого списка, который ограничивает возможные значения.
// Value whitelist
// $dir can only be 'DESC' otherwise it will be 'ASC'
if (empty($dir) || $dir !== 'DESC') {
$dir = 'ASC';
}
Сегодня у меня была такая же проблема, и я многому научился.
В Visual Studio есть два типа проектов - «Проекты веб-сайтов» и «Проекты веб-приложений». По причинам, которые для меня являются полной загадкой, проекты веб-приложений не могут использовать профиль . напрямую ... строго типизированный класс не создается для вас волшебным образом из файла Web.config, поэтому вам придется использовать собственный.
Пример кода в MSDN предполагает, что вы используете проект веб-сайта, и они сообщают вам просто нужно добавить раздел
в свой Web.config
и использовать свойство Profile.
, но это не работает в Проекты веб-приложений.
У вас есть два варианта развертывания собственных:
(1) Используйте Конструктор веб-профилей . Это настраиваемый инструмент, который вы добавляете в Visual Studio, который автоматически генерирует нужный объект профиля из вашего определения в Web.config.
Я решил не делать этого, потому что не хотел, чтобы мой код зависел от этого дополнительного инструмента. для компиляции, что могло вызвать проблемы у кого-то в будущем, когда они попытались построить мой код, не осознавая, что им нужен этот инструмент.
(2) Создайте свой собственный класс, производный от ProfileBase
для представляют ваш индивидуальный профиль. Это проще, чем кажется. Вот очень простой пример, который добавляет строковое поле профиля «FullName»:
В вашем web.config:
<profile defaultProvider="SqlProvider" inherits="YourNamespace.AccountProfile">
<providers>
<clear />
<add name="SqlProvider"
type="System.Web.Profile.SqlProfileProvider"
connectionStringName="sqlServerMembership" />
</providers>
</profile>
В файле с именем AccountProfile.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Profile;
using System.Web.Security;
namespace YourNamespace
{
public class AccountProfile : ProfileBase
{
static public AccountProfile CurrentUser
{
get { return (AccountProfile)
(ProfileBase.Create(Membership.GetUser().UserName)); }
}
public string FullName
{
get { return ((string)(base["FullName"])); }
set { base["FullName"] = value; Save(); }
}
// add additional properties here
}
}
Чтобы установить значение профиля:
AccountProfile.CurrentUser.FullName = "Snoopy";
Чтобы получить значение профиля
string x = AccountProfile.CurrentUser.FullName;
То, когда Вы создаете новый проект веб-сайта в Visual Studio тогда объект, который возвращается из Профиля, будет (автоматически) сгенерировано для Вас. При создании проекта веб-приложения или проекта MVC Вы будете иметь к самокрутке.
Это, вероятно, звучит более трудным, чем это. Необходимо сделать следующее:
При использовании проекта веб-приложения Вы не можете получить доступ к объекту Профиля во время проектирования out-of-the-box. Вот утилита, которая, предположительно, делает это для Вас: http://weblogs.asp.net/joewrobel/archive/2008/02/03/web-profile-builder-for-web-application-projects.aspx . Лично, та утилита вызвала ошибку в моем проекте, таким образом, я закончил тем, что прокрутил свой собственный класс профиля для наследования ProfileBase. Не было трудно сделать вообще.
Конструктор веб-профилей отлично поработал у меня. Сгенерированный им класс содержит гораздо больше, чем описано в сообщении Джоэла. Я не знаю, действительно ли он нужен или полезен.
В любом случае, для тех, кто ищет простой способ создания класса, но не хочет иметь зависимость от внешнего инструмента сборки, вы всегда можете
ИЛИ (непроверенный, но может работать)
, если этот второй подход работает, может ли кто-нибудь сообщить мне для справок в будущем
Пошаговое руководство MSDN для создания настраиваемого класса (также известного как метод Джоэла):
http://msdn.microsoft.com/en-us/magazine/cc163624.aspx
Отличный пост,
Только замечание по web.config если вы не укажете атрибут inherit в элементе профиля. вам нужно будет указать каждое отдельное свойство профиля внутри элемента профиля в web.config, как показано ниже
<properties>
<clear/>
<add name="property-name-1" />
<add name="property-name-2" />
..........
</properties>