Используйте подготовленные операторы и параметризованные запросы. Это операторы 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';
}
У меня нет достаточной репутации, чтобы "прокомментировать" ответ Raim выше, но его работавший отлично, за одним исключением, его grep шаблон является неправильным.
я просто использовал ниже в качестве своего рычага перед фиксацией (у меня не было существующего, необходимо будет объединиться в этом случае):
#!/bin/sh
REPOS="$1"
TXN="$2"
SVNLOOK=/opt/local/bin/svnlook
# Committing to tags is not allowed
$SVNLOOK changed -t "$TXN" "$REPOS" | grep "^U\W.*\/tags\/" && /bin/echo "Cannot commit to tags!" 1>&2 && exit 1
# All checks passed, so allow the commit.
exit 0
единственная проблема с grep шаблоном Raim состоит в том, что он только соответствовал "тегам", если это было в "корне" Вашего repo. Так как у меня есть несколько проектов в моем repo, сценарий, поскольку он записал, что он позволил фиксации на ответвлениях тега.
кроме того, быть уверенными chmod +x, как обозначено, иначе Вы будете думать, что он работал b/c отказавшая фиксация, но он привел b/c к сбою, он не мог должностное лицо рычаг перед фиксацией, не потому что рычаг работал.
Это было действительно большим, Raim спасибо. Намного лучше и более легкий вес, чем все другие предложения, поскольку это не имеет никаких зависимостей!
Вот короткий сценарий оболочки для предотвращения согласия на теги после того, как они были созданы:
#!/bin/sh
REPOS="$1"
TXN="$2"
SVNLOOK=/usr/bin/svnlook
# Committing to tags is not allowed
$SVNLOOK changed -t "$TXN" "$REPOS" | grep "^U\W*tags" && /bin/echo "Cannot commit to tags!" 1>&2 && exit 1
# All checks passed, so allow the commit.
exit 0
Сохраняют это в hooks/pre-commit
для Вашего репозитория Подверсии и делают это исполняемым файлом с chmod +x
.
Довольно поздно стороне, однако я записал рычаг Python перед фиксацией для работы, которая базируется от сценария журнала-police.py на http://subversion.tigris.org/ .
Этот сценарий должен сделать то, что Вы хотите, однако он также проверяет, что сообщение журнала существует, хотя это должно быть легко удалить из сценария.
Некоторые протесты:
Требования:
Наконец, кода:
#!/usr/bin/env python
#
# pre-commit.py:
#
# Performs the following:
# - Makes sure the author has entered in a log message.
# - Make sure author is only creating a tag, or if deleting a tag, author is a specific user
#
# Script based on http://svn.collab.net/repos/svn/trunk/tools/hook-scripts/log-police.py
#
# usage: pre-commit.py -t TXN_NAME REPOS
# E.g. in pre-commit.bat (under Windows)
# python.exe {common_hooks_dir}\pre_commit.py -t %2 %1
#
import os
import sys
import getopt
try:
my_getopt = getopt.gnu_getopt
except AttributeError:
my_getopt = getopt.getopt
import re
import svn
import svn.fs
import svn.repos
import svn.core
#
# Check Tags functionality
#
def check_for_tags(txn):
txn_root = svn.fs.svn_fs_txn_root(txn)
changed_paths = svn.fs.paths_changed(txn_root)
for path, change in changed_paths.iteritems():
if is_path_within_a_tag(path): # else go to next path
if is_path_a_tag(path):
if (change.change_kind == svn.fs.path_change_delete):
if not is_txn_author_allowed_to_delete(txn):
sys.stderr.write("\nOnly an administrator can delete a tag.\n\nContact your Subversion Administrator for details.")
return False
elif (change.change_kind != svn.fs.path_change_add):
sys.stderr.write("\nUnable to modify " + path + ".\n\nIt is within a tag and tags are read-only.\n\nContact your Subversion Administrator for details.")
return False
# else user is adding a tag, so accept this change
else:
sys.stderr.write("\nUnable to modify " + path + ".\n\nIt is within a tag and tags are read-only.\n\nContact your Subversion Administrator for details.")
return False
return True
def is_path_within_a_tag(path):
return re.search('(?i)\/tags\/', path)
def is_path_a_tag(path):
return re.search('(?i)\/tags\/[^\/]+\/?, path)
def is_txn_author_allowed_to_delete(txn):
author = get_txn_property(txn, 'svn:author')
return (author == 'bob.smith')
#
# Check log message functionality
#
def check_log_message(txn):
log_message = get_txn_property(txn, "svn:log")
if log_message is None or log_message.strip() == "":
sys.stderr.write("\nCannot enter in empty commit message.\n")
return False
else:
return True
def get_txn_property(txn, prop_name):
return svn.fs.svn_fs_txn_prop(txn, prop_name)
def usage_and_exit(error_msg=None):
import os.path
stream = error_msg and sys.stderr or sys.stdout
if error_msg:
stream.write("ERROR: %s\n\n" % error_msg)
stream.write("USAGE: %s -t TXN_NAME REPOS\n"
% (os.path.basename(sys.argv[0])))
sys.exit(error_msg and 1 or 0)
def main(ignored_pool, argv):
repos_path = None
txn_name = None
try:
opts, args = my_getopt(argv[1:], 't:h?', ["help"])
except:
usage_and_exit("problem processing arguments / options.")
for opt, value in opts:
if opt == '--help' or opt == '-h' or opt == '-?':
usage_and_exit()
elif opt == '-t':
txn_name = value
else:
usage_and_exit("unknown option '%s'." % opt)
if txn_name is None:
usage_and_exit("must provide -t argument")
if len(args) != 1:
usage_and_exit("only one argument allowed (the repository).")
repos_path = svn.core.svn_path_canonicalize(args[0])
fs = svn.repos.svn_repos_fs(svn.repos.svn_repos_open(repos_path))
txn = svn.fs.svn_fs_open_txn(fs, txn_name)
if check_log_message(txn) and check_for_tags(txn):
sys.exit(0)
else:
sys.exit(1)
if __name__ == '__main__':
sys.exit(svn.core.run_app(main, sys.argv))
Этот ответ очень устарел, но я обнаружил параметр --copy-info для команды svnlook changed.
В выводе этой команды в третьем столбце добавляется знак «+», так что вы знаете, что это копия. Вы можете проверить наличие коммитов в каталоге тегов и разрешить коммиты только со знаком «+».
Я добавил некоторые результаты в свой блог .
Вот мой хук предварительной фиксации командного файла Windows. Если пользователь является администратором, другие проверки будут пропущены. Он проверяет, является ли сообщение фиксации пустым, а фиксация - тегом. Примечание: findstr - это уменьшенная альтернатива grep на других платформах.
Метод, которым он проверяет, соответствует ли фиксация тегу, сначала проверяет, содержит ли svnlook changed "теги /". Затем он проверяет, соответствует ли изменение svnlook «^ A. tags / [^ /] / $», что означает, что он проверит, добавляете ли вы новую папку в теги /.
Пользователи могут создавать новые проекты. Ловушка предварительной фиксации позволяет пользователю создавать папки trunk / tags / и branch /. Пользователям не разрешается удалять папки trunk / tags / и branch /. Это будет работать для репозитория с одним или несколькими проектами.
@echo off
rem This pre-commit hook will block commits with no log messages and blocks commits on tags.
rem Users may create tags, but not modify them.
rem If the user is an Administrator the commit will succeed.
rem Specify the username of the repository administrator
rem commits by this user are not checked for comments or tags
rem Recommended to change the Administrator only when an admin commit is neccessary
rem then reset the Administrator after the admin commit is complete
rem this way the admin user is only an administrator when neccessary
set Administrator=Administrator
setlocal
rem Subversion sends through the path to the repository and transaction id.
set REPOS=%1%
set TXN=%2%
:Main
rem check if the user is an Administrator
svnlook author %REPOS% -t %TXN% | findstr /r "^%Administrator%$" >nul
if %errorlevel%==0 (exit 0)
rem Check if the commit has an empty log message
svnlook log %REPOS% -t %TXN% | findstr . > nul
if %errorlevel% gtr 0 (goto CommentError)
rem Block deletion of branches and trunk
svnlook changed %REPOS% -t %TXN% | findstr /r "^D.*trunk/$ ^D.*branches/$" >nul
if %errorlevel%==0 (goto DeleteBranchTrunkError)
rem Check if the commit is to a tag
svnlook changed %REPOS% -t %TXN% | findstr /r "^.*tags/" >nul
if %errorlevel%==0 (goto TagCommit)
exit 0
:DeleteBranchTrunkError
echo. 1>&2
echo Trunk/Branch Delete Error: 1>&2
echo Only an Administrator may delete the branches or the trunk. 1>&2
echo Commit details: 1>&2
svnlook changed %REPOS% -t %TXN% 1>&2
exit 1
:TagCommit
rem Check if the commit is creating a subdirectory under tags/ (tags/v1.0.0.1)
svnlook changed %REPOS% -t %TXN% | findstr /r "^A.*tags/[^/]*/$" >nul
if %errorlevel% gtr 0 (goto CheckCreatingTags)
exit 0
:CheckCreatingTags
rem Check if the commit is creating a tags/ directory
svnlook changed %REPOS% -t %TXN% | findstr /r "^A.*tags/$" >nul
if %errorlevel% == 0 (exit 0)
goto TagsCommitError
:CommentError
echo. 1>&2
echo Comment Error: 1>&2
echo Your commit has been blocked because you didn't enter a comment. 1>&2
echo Write a log message describing your changes and try again. 1>&2
exit 1
:TagsCommitError
echo. 1>&2
echo %cd% 1>&2
echo Tags Commit Error: 1>&2
echo Your commit to a tag has been blocked. 1>&2
echo You are only allowed to create tags. 1>&2
echo Tags may only be modified by an Administrator. 1>&2
echo Commit details: 1>&2
svnlook changed %REPOS% -t %TXN% 1>&2
exit 1