Escolar Documentos
Profissional Documentos
Cultura Documentos
Segurança em PHP
Para tornar um aplicativo em PHP mais seguro temos que tomar várias providências. E isso não se
aplica exclusivamente ao PHP, mas a praticamente todas as linguagens ou ferramentas de
programação. Os cuidados aqui dizem respeito mais a aplicativos web.
Com PHP é possível acessar arquivos, executar comandos e abrir conexões de rede no servidor.
Essas propriedades fazem qualquer coisa executando em um servidor web inseguras por padrão.
Quando estiver testando, tenha em mente que você não será capaz de testar todas as possibilidades
nem mesmo para as páginas mais simples.
2
Usando a diretiva open_basedir você pode controlar e restringir quais diretórios o PHP tem
permissão de usar. Você também pode configurar area exclusivas para o Apache, restringir todas as
atividades web para arquivo que não sejam de algum usuário ou do sistema.
Checagem mais segura do nome do arquivo
<?php
$username = $_SERVER['REMOTE_USER']; // usando um mecanismo de autenticação
$userfile = $_POST['user_submitted_filename'];
$homedir = "/home/$username";
$filepath = "$homedir/$userfile";
if (!ctype_alnum($username) || !preg_match('/^(?:[a-z0-9_-]|\.(?!\.))+$/iD', $userfile)) {
die("Bad username/filename");
}
//etc...
?>
Validando entrada corretamente
<?php
$file = $_GET['file'];
SSL/SSH protege dados transitando de um cliente para o servidor, mas não protege os dados
guardados em um banco de dados. SSL é um protocolo on-the-wire.
Uma vez que o atacante ganha acesso direto ao seu banco de dados(desviando do servidor web), os
dados armazenados podem ser expostos ou sofre uso nocivo, a não ser que a informação seja
protegida pelo banco em si. Criptografa os dados é uma boa maneira de diminuir essa ameaça, mas
poucos bancos de dados oferecem esse tipo de criptografia de dados.
A maneira mais fácil de contornar esse problema é primeiro criar seu próprio pacote de criptografia,
e então usá-lo no seus scripts PHP. O PHP pode ajudá-lo com várias extensões, tais como Mcrypt e
Mhash, cobrindo uma grande variedade de algoritmos de criptografia. O script criptografa os dados
antes de inserí-los no banco de dados e descriptografa quando os recupera. Veja as referência para
outros exemplos de como criptografia funciona.
No caso de dados realmente escondidos, se sua representação crua não é necessária (ex.: não será
3
mostrada), usar uma função de hash pode ser levada em consideração. Um exemplo bem conhecido
disso é guardar o hash MD5 de uma senha no banco de dados ao invés da senha em si. Veja também
crypt() e md5().
if (pg_num_rows($result) > 0) {
echo 'Welcome, $username!';
} else {
echo 'Authentication failed for $username.';
}
?>
crypt
crypt() retornará uma string criptografada usando o algoritmo de encriptação Unix Standard DES-
based ou ou algoritmos alternativos disponíveis no sistema. Os argumentos são uma string para ser
criptografada e uma string opcional para basear em qual encriptação está. Veja a página de
encriptação Unix para mais informação.
Se o argumento salt não é fornecido, um argumento aleatório será gerado pelo PHP.
Em sistemas onde a função crypt() suporta variados tipos de codificação, as seguintes funções são
definidas para 0 ou 1 a depender se um dado tipo está disponível:
Nota: Não há função de decodificação, desde que crypt() utiliza uma algorimo de mão única.
crypt() exemplos
<?php
$password = crypt("My1sTpassword"); // let salt be generated
# You should pass the entire results of crypt() as the salt for comparing a
# password, to avoid problems when different hashing algorithms are used. (As
# it says above, standard DES-based password hashing uses a 2-character salt,
# but MD5-based hashing uses 12.)
if (crypt($user_input, $password) == $password) {
echo "Password verified!";
}
?>
md5
Calcula o "hash MD5" de str usando » RSA Data Security, Inc. MD5 Message-Digest Algorithm, e
devolve esse hash. O hash é um número hexadecimal 32-character. Se o opcional raw_output está
definido para TRUE, então o md5 compreende que ao invés disso retorna um "raw binary format"
com comprimento 16.
Nota: O parâmetro opcional raw_output foi adicionado no PHP 5.0.0 e por definição é FALSE
Um exemplo de md5()
<?php
$str = 'apple';
Injeção de SQL
Muitos desenvolvedores web não sabem de como consultas SQL podem ser manipuladas, e
presumem que uma consulta de SQL é um comando confiável. Significa que consultas SQL são
capazes de passar indetectado por controles de acesso, portanto desviando da autenticação padrão e
teestes de autorização, e algumas vezes consultas SQL podem permitir acesso à comando em nível
do sistema operacional do servidor.
Injeção direta de comandos SQL é uma técnica onde um atacante cria ou alterar comandos SQL
existentes para expor dados escondidos, ou sobrescrever dados valiosos, ou ainda executar
5
?>
Nunca confie em nenhum tipo de entrada, especialmente aquela que vem do lado do cliente, mesmo
que venha de um combobox, um campo de entrada escondido (hidden) ou um cookie. O primeiro
exemplo mostra como uma consulta inocente pode causar desastres.
* Nunca conecte ao banco de dados como um super-usuário ou como o dono do banco de dados.
Sem use usuários personalidados com privilégios bem limitados.
* Verifique se uma entrada qualquer tem o tipo de dados experado. O PHP tem um grande
número de funções de validação de entrada, desde as mais simples encontrada em Funções de
Variáveis e em Funções de Tipo de Caracteres (ex.: is_numeric(), ctype_digit() respectivamente)
além de usar o suporte à Expressões Regulares Compatível com Perl.
*
Se a aplicação espera por entradas numéricas, considere verificar os dados com a função
is_numeric(), ou silenciosamente mudar o seu tipo usando settype(), ou usar a representação
númeria usando a função sprintf().
settype($offset, 'integer');
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";
?>
* Adicione aspas para cada valor não numérico especificado pelo usuário que será passado para
o banco de dados com as funções de caracteres de escape (ex.: mysql_escape_string(),
sql_escape_string(), etc.). Se um mecanismo de escape de caracter específico par ao seu banco de
6
dados não for disponível, as funções addslashes() e str_replace() podem ser úteis (dependendo do
tipo de banco de dados). Veja o o primeiro exemplo. Como o exemplo mostra, adicionar aspas para
a parte estática da consulta não é suficiente, fazendo com que a consulta seja facilmente atacada.
* Não imprima qualquer informação específica do banco de dados, especialmente sobre o
esquema, custe o que custar. Veja também Relatório de Erros e Funções de Tratamento e Relatório
de Erros.
* Você pode usar stored procedures e cursores previamente definidas para abstrair acesso aos
dados para que os usuário não acessem tabelas ou view diretamente, mas essa solução pode ter
outros impactos.
Além disso, você ganha em relatar consultas ou dentro do script ou no próprio banco de dados, se
esse suportar. Obviamente, o relatório é para previnir qualquer tentativa danosa, mas pode ser útil
para ajudar a rastrar qual aplicação foi atacada. O resitro não é útil em si, mas atráves da informação
que ele contem. Mais detalhes geralmente é melhor que menos.
Relatando Erros
Com relação a segurança, relatório de erros é uma faca de dois gumes. Pode beneficiar o aumento
da segurança, ou fornecer informaçao ao atacante.
Uma tática padrão de ataque involve determinar como um sistema funciona entrando dados
incorretos e checando os tipos e contextos dos erros que são retornados. Isso permite que um
cracker sonde por informações sobre o servidor, para determinar possíveis fraquezas.
Os erros do PHP que são retornados normalmente podem ser úteis para um desenvolvedor que está
tentando depurar um script, indicando coisas como a função ou arquivo que falhou, o arquivo PHP
no qual a falha ocorreu, e o número da linha de código causadora da falha. Toda essa informação
pode ser explorada. Não é incomum para um desenvolvedor PHP usar show_source(),
highlight_string(), ou highlight_file() como medidas de depuração, mas em um site de produção,
isso pode expor variáveis ocultas, sintaxe incorreta, ou outra informações perigosas. Especialmente
perigoso é rodar código de fontes conhecidas com tratadores de depuração integrados, ou usar
técnicas de depuração comuns.
Existem três soluções principais para esse problema. A primeira é verificar exaustivamente todas as
funções, e tentar compensar pelo volume dos erros. A segunda é desabilitar completamente os
relatórios de erros no código de produção. A terceira é usar as funções personalizávies de tratamento
de erro do PHP para criar seu próprio tratador de erro. Dependendo da sua política de segurança,
você pode perceber que todas são aplicáveis à sua situação.
Uma maneira de perceber esse problema antes que o pior aconteça é usar a diretiva
error_reporting(), para ajudar a aumentar a segurança de seu código e achar uso de variáveis que
pode ser perigoso. Ao testar o seu código, antes de colocar em produção, com E_ALL, você pode
rapidamente encontrar áreas onde suas variáveis podem sofrer alterações nocivas ou modificações
quaisquer. Uma vez que estiver pronto para produção, você deve ou desabilitar mensagens de erro
completamente configurando a diretiva error_reporting() com o valor 0, ou desligar o envio de erros
usando a opção display_errors do arquivo php.ini, para evitar sondagem do seu código. Se você
escolher a segunda opção, você deve também definir o caminho para o arquivo de registro usando a
diretiva error_log, e ligar a diretiva log_errors.
7
Tenha em mente que a diretiva em si não é insegura, o uso incorreto dela é que é.
Quando ligada, a diretiva register_globals criará para seus scripts vários tipos de variáveis, como as
variáveis oriundas de formulários HTML. Isso, combinado com o fato de que o PHP não requer
inicialização de variáveis, significa que é mais fácil escrever código inseguro. Foi uma decisão
difícil, mas a comunidade do PHP decidiu que, por padrão, essa diretiva deveria ser desabilitada.
Quando habilitada, é possível usar variáveis sem saber ao certo de onde elas vieram. Variáveis
internas que são definidas no script em si se misturam com dados enviados pelos usuários e
desabilitando a diretiva muda isso. Vamos demonstrar um exemplo de uso incorreto de
register_globals:
A maior fraqueza na maioria dos programas PHP não é inerente a linguagem em si, mas meramente
um problema de código escrito desconsiderando segurança. Por essa razão, você sempre deve
investir um pouco de tempo considerando as implicações de um certo pedaço de código, para ter
certeza que o dano possível se uma variável não esperada for submetida ao mesmo.
unlink ($evil_var);
?>
Você sempre deve examinar cuidadosamente seu código para se assegurar que quaisquer variáveis
sendo enviadas do navegador web estão sendo checadas de maneira correta, e faz a si mesmo as
seguintes perguntas:
Magic Quotes
Magic Quotes é um processo de inserção automática de caracteres de escape (\) em todos os dados
indo para o script PHP. É preferível escrever código com essa opção desligada e adicionar esses
caracteres manualmente quando necessário.
Quando ligada, qualquer ' (aspas simples), " (aspas duplas), \ (barra invertida) e NULL será
colocado uma barra-invertida antes (' vira \') automaticamente. Isso é identico ao que a função
addslashes() faz.
* magic_quotes_gpc Afeta os dados de requisições HTTP GET, POST, e COOKIE). Não pode ser
alterada em tempo de execução e tem o valor padrão on no PHP. Veja também
get_magic_quotes_gpc().
* magic_quotes_runtime Se habilitada, a maioria das funções que retorna dados de uma fonte
9
externa, incluindo bancos de dados e arquivos de texto, serão alterados. Pode ser alterado em tempo
de execução e tem o valor padrão de off no PHP. Veja também set_magic_quotes_runtime() e
get_magic_quotes_runtime().
* magic_quotes_sybase Se habilitada, uma aspa simples é usada como caracter de escape quando
encontrar outra aspa simples (' vira ''). Se ligada, sobrepõe completamente magic_quotes_gpc. Ligar
ambas as diretivas significa que apenas aspas simples são substituídas por ''. Aspas duplas, barras
invertidas e NULLs permanecerão intocados e não serão escapados. Veja também ini_get() para
pegar esse valor.
* Performance Como nem todos os dados escapados são inseridos em um banco de dados,
existe uma perda de performance por escapar todos os dados. Chamar funções de escape (como
addslashes()) em tempo de execução é mais eficiente. Embora o arquivo php.ini-dist habilita essas
diretivas por padrão, php.ini-recommended desabilita ela. Essa recomendação é principalmente por
razões de performance.
* Inconviniência Porque nem todos os dados precisam ter caracteres de escape inseridos, é
irritante ver caracteres de escape onde não deviam. Por exemplo, mandar um e-mail por um
formulário, e ver um monte de \' na mensagem. Para consertar isso, pode ser necessário o uso
excessivo da função stripslashes().
Um exemplo que configuração dessa diretiva para Off (Desligada) no arquivo php.ini. Para detalhes
adicionais, leia a seção do manual entitulada Como mudar os valores das configurações.
; Magic quotes
;
; Magic quotes para dados gerados em tempo de execução,ex.: dados vindo de SQL, de chamadas à
exec(), etc.
magic_quotes_runtime = Off
; Usar magic quotes no estilo Sybase (escapar ' com '' ao invés de \').
magic_quotes_sybase = Off
Esse método é ineficiente então é preferível configurar as diretivas apropriadas em outros lugares.
<?php
if (get_magic_quotes_gpc()) {
function stripslashes_deep($value)
{
$value = is_array($value) ?
array_map('stripslashes_deep', $value) :
stripslashes($value);
return $value;
}
Mantendo-se Atualizado
PHP, como qualquer outro sistema grande, está sobre constante revisão e melhoramento. Cada
versão nova normalmente incluirá mudanças, sejam grandes ou pequenas, para melhorar a
segurança e reparar falhas, erros de configuração, e outros problemas que podem afetar a segurança
geral e estabilitade do seu sistema.
Como outras linguagens de script e programas de nível de sistema, a melhor política é atualizar
frequentemente e manter-se atento as novas versões e suas mudanças.
0 – Instalação e configurações dos softwares. Atentar para detalhes que reforças a segurança tantos
nos softwares quanto nos servidores onde estão instalados.
1 – Elaborar com cuidado e zelo o projeto do banco e do aplicativo, atentando para:
- padronizações
- documentação
- ter alguém responsável por se manter atualizado em relação às tecnologias envolvidas no
projeto: PHP, SGBD, ferramentas utilizadas, etc. Procurar atualizar com frequência.
- Cuidado ao aproveitar programas ou códigos de terceiros. Analise bem seu conteúdo.
- Nunca utilizar includes com extensão texto (inc, txt, etc)
2 - Backup – Efetuar cópias de segurança regularmente é algo que não pode faltar.
3 – Caso não vá usar desabilite o acesso via FTP
4 – Utilizar boas ferramentas que ajudam a monitorar a segurança como:
- phpSecInfo
- securityScanner
5 – Sempre que for utilizar senha com hash MD5, procurar no site Reverse MD5 para ver se já não
está no banco de dados.
6 – Antes de armazenar no banco de dados dados entrados pelo usuário tomar vários cuidados:
11
get_magic_quotes_gpc()
get_magphpic_quotes_runtime()
if (!get_magic_quotes_gpc()) {
$sobrenome = addslashes($_POST['sobrenome']);
} else {
$lastname = $_POST['sobrenome'];
}
ini_set
Bons servidores de hospedagem ou revenda atualmente permitem entrar com um php.ini para cada
diretório. No caso, apenas entramos com os parâmetros desejados no php.ini.
Mas quando não tivermos este recurso nem acesso direto ao php.ini podemos usar a função
ini_set(), que não simula todos os parâmetros do php.ini mas pode alterar vários.
ini_set("display_errors", "Off");
Outra:
12
$inis = ini_get_all();
print_r($inis);
realpath_cache_size - 16K
realpath_cache_ttl – 120
Determines the size of the realpath cache to be used by PHP. This value should be increased
on systems where PHP opens many files, to reflect the quantity of the file operations
performed.
realpath_cache_ttl integer
Duration of time (in seconds) for which to cache realpath information for a given file or
directory. For systems with rarely changing files, consider increasing the value.
Controle de erros:
Na fase de testes
error_reporting = E_ALL
Em produção:
error_reporting = E_ALL & ~E_NOTICE (o mínimo possível)
Além disso camuflar todos os possíveis erros com @ colado à esquerda do nome de funções com a
possibilidade de erro, especialmente funções de acesso a banco de dados.
log_errors = On
Ajuda a encontrar causas de problemas.
safe_mode = On
Safe_mode inpões uma série de restrições com o intuido de tornar os scripts mais seguros.
Com o safe_mode ativo somente podemos executar executáveis no diretório apontado por:
safe_mode_exec_dir = diretorio
Variáveis
Formulários
Não guardar informações confidenciais nem nos scripts "nem no banco de dados".
Guardar sigilo sobre nosso código PHP e manter uma senha para acesso aos scripts e ao banco de
dados (usar a ferramenta Proteger diretório do cPanel).
O arquivo onde guardamos a senha de acesso ao banco não deve conter o código, mas deve ficar
separado, somente com o acesso ao banco, tipo conexao.inc.php e ficar fora do diretório do
aplicativo, um nível antes, chamado com require_once. Fica mais difícil de alguém mexer.
<?php
$clean = array();
$email_pattern = '/^[^@\s<&>]+@([-a-z0-9]+\.)+[a-z]{2,}$/i';
14
if (preg_match($email_pattern, $_POST['email']))
{
$clean['email'] = $_POST['email'];
}
?>
<?php
$clean = array();
switch ($_POST['color'])
{
case 'red':
case 'green':
case 'blue':
$clean['color'] = $_POST['color'];
break;
}
?>
Garantir que $_POST['num'] is an integer:
<?php
$clean = array();
if ($_POST['num'] == strval(intval($_POST['num'])))
{
$clean['num'] = $_POST['num'];
}
?>
<?php
$clean = array();
if ($_POST['num'] == strval(floatval($_POST['num'])))
{
$clean['num'] = $_POST['num'];
}
?>
Form seguro:
<?php
$token = md5(time());
$fp = fopen('./tokens.txt', 'a');
fwrite($fp, "$token\n");
fclose($fp);
?>
<form method="POST">
15
<?php
$tokens = file('./tokens.txt');
if (in_array($_POST['token'], $tokens))
{
if (isset($_POST['message']))
{
$message = htmlentities($_POST['message']);
$fp = fopen('./messages.txt', 'a');
fwrite($fp, "$message<br />");
fclose($fp);
}
}
readfile('./messages.txt');
?>
Outro exemplo:
<?php
session_start();
if (isset($_POST['message']))
{
if (isset($_SESSION['token']) && $_POST['token'] == $_SESSION['token'])
{
$message = htmlentities($_POST['message']);
$fp = fopen('./messages.txt', 'a'); // O arquivo deve existir
fwrite($fp, "$message<br />");
fclose($fp);
}
}
$token = md5(uniqid(rand(), true));
$_SESSION['token'] = $token;
?>
<form method="POST">
<input type="hidden" name="token" value="<?php echo $token; ?>" />
<input type="text" name="message"><br />
<input type="submit">
</form>
<?php
readfile('./messages.txt');
?>
<?php
/* Store user details */
$passwordHash = sha1($_POST['password']);
$sql = 'INSERT INTO user (username,passwordHash) VALUES (?,?)';
$result = $db->query($sql, array($_POST['username'], $passwordHash));
?>
The next time our user logs in, we check their access credentials using similar code as follows:
<?php
/* Check user details */
$passwordHash = sha1($_POST['password']);
$sql = 'SELECT username FROM user WHERE username = ? AND passwordHash = ?';
$result = $db->query($sql, array($_POST['username'], $passwordHash));
if ($result->numRows() < 1)
{
/* Access denied */
echo 'Sorry, your username or password was incorrect!';
}else{
/* Log user in */
printf('Welcome back %s!', $_POST['username']);
}
?>
Tipos de Hash
In PHP you can generate hashes using the md5() and sha1 functions. md5() returns a 128-bit hash
(32 hexadecimal characters), whereas sha1() returns a 160-bit hash (40 hexadecimal characters). For
example:
<?php
$string = 'PHP & Information Security';
printf("Original string: %s\n", $string);
printf("MD5 hash: %s\n", md5($string));
printf("SHA-1 hash: %s\n", sha1($string));
?>
In MySQL you can generate hashes internally using the password(), md5(), or sha1 functions.
password() is the function used for MySQL's own user authentication system. It returns a 16-byte
string for MySQL versions prior to 4.1, and a 41-byte string (based on a double SHA-1 hash) for
versions 4.1 and up. md5() is available from MySQL version 3.23.2 and sha1() was added later in
4.0.2.
You may decide to use MySQL to calculate your hash rather than PHP. The example of storing our
17
<?php
/* Store user details */
$sql = 'INSERT INTO user (username, passwordHash) VALUES (?, SHA1(?))';
$result = $db->query($sql, array($_POST['username'], $_POST['password']));
?>
When we validate a user's login credentials we follow the same process, only this time we use the
salt from our database instead of generating a new random one. We add the user supplied password
to it, run our hashing algorithm, then compare the result with the hash stored in that user's profile.
<?php
define('SALT_LENGTH', 9);
function generateHash($plainText, $salt = null)
{
if ($salt === null)
{
$salt = substr(md5(uniqid(rand(), true)), 0, SALT_LENGTH);
}
else
{
$salt = substr($salt, 0, SALT_LENGTH);
}
return $salt . sha1($salt . $plainText);
}
?>
Captcha – Form
captcha.php
<?php
session_start();
?>
<html><head>
<title>Gateway</title>
</head>
<body>
Please enter the value you see below:<br />
<img src="captcha-image.php" />
<form action="" method="post">
<input type="text" name="number" value="" /><br />
<button type="submit">Submit</button>
</form>
<?php
if (isset($_POST['number']))
if ($_SESSION['number'] == $_POST['number'])
18
echo "Correct";
else
echo "Wrong value entered!";
?>
</body></html>
captcha_image.php
<?php
session_start();
$number = rand(1,999); //generate a random integer
$_SESSION['number'] = $number; //store in session variable
$img_number = imagecreate(40,25);
$backcolor = imagecolorallocate($img_number,0xcc,0xcc,0xcc);
$textcolor = imagecolorallocate($img_number,255,255,255);
imagefill($img_number,0,0,$backcolor);
imagestring($img_number,10,5,5,$number,$textcolor);
header("Content-type: image/jpeg");
imagejpeg($img_number);
?>
<?
//login $_POST['username']
//password $_POST['password']
//I passed $_POST through smart_quotes first before sending to SQL query.
//$_POST=mcheck($_POST)
//after mcheck(), do the SQL queries...
function mcheck($value) {
if(is_array($value)) {
if(get_magic_quotes_gpc()) {
$value=array_map("stripslashes",$value);
}
if(!array_map("is_numeric",$value)) {
$value=array_map("mysql_real_escape_string",$value);
}
} else {
if(get_magic_quotes_gpc()) {
$value=stripslashes($value);
}
if(!is_numeric($value)) {
$value="'" . mysql_real_escape_string($value) . "'";
}
}
return $value;
}
19
?>
mysql_real_escape_string() is enough for queries but before you print that, use
"htmlspecialchars();" or "htmlentities();".
For example:
echo htmlspecialchars($username);
Also, never code with register_globals on. If your server must have register_globals on, always
have unique names for session variables (such as SESS_varname) and always declare a variable
before using it (ex: $output = ''; $output .= 'hello!'; )
<?
function secured($val)
{
if(empty($val) or strlen($val) > 40)
{
return false;
} else {
$val = strip_tags(trim(($val)));
$val = escapeshellcmd($val);
return stripslashes($val);
}
}
?>
So, using this function is simple. Any text box as a name, this is the html code
ex. <input name="securityscript" type="text" id="securityscript">
When the user clicks send button the fill box has a value. All you have to do is to filter that value
this way calling the function.
if(isset($Submit))
{
secured($securityscript);
// rest of your code
If you want to test this script type a text of your choice and it'll be shown normally. The try with
something like <img> or any tag you like. If nothing happens this mean that your input has been
20
Original - http://www.phpmag.net/itr/online_artikel/psecom,id,667,nodeid,114.html
<?php
/* run a self-test through every listed
* cipher and mode
*/
function mcrypt_check_sanity() {
$modes = mcrypt_list_modes();
$algorithms = mcrypt_list_algorithms();
/* Encrypt data */
$c_t = mcrypt_generic($td, $plain_text);
mcrypt_generic_deinit($td);
/* Clean up */
mcrypt_generic_end($td);
mcrypt_module_close($td);
}
if (strncmp($p_t, $plain_text,strlen($plain_text)) == 0) {
return TRUE;
} else {
return FALSE;
}
}
// function call:
mcrypt_check_sanity();
?>
Encriptando Cookies
<?php
function my_encrypt($string) {
$key = 'supersecret';
$key = md5($key);
/* Encrypt data */
$c_t = mcrypt_generic($td, $string);
22
mcrypt_generic_end($td);
mcrypt_module_close($td);
return $c_t;
} //end if
}
function my_decrypt($string) {
$key = 'supersecret';
$key = md5($key);
/* Encrypt data */
$c_t = mdecrypt_generic($td, $string);
mcrypt_generic_end($td);
mcrypt_module_close($td);
return trim($c_t); //trim to remove
//padding
} //end if
}
function my_encryptcookie($string) {
return base64_encode(my_encrypt($string));
}
function my_decryptcookie($string) {
return my_decrypt(base64_decode($string));
}
?>
set_twofish_cookie.php
<?php
include("twofish_cookie.php");
if($_COOKIE['test']) print
my_decryptcookie($_COOKIE['test']);
else {
$s = my_encryptcookie("Hello, world.");
if(setcookie('test', $s, time()+3600)) {
print 'Cookie set.';
}
}
?>
23
<?php
function my_encrypt($string) {
srand((double) microtime() * 1000000);
//for sake of MCRYPT_RAND
$key = 'supersecret';
$key = md5($key);
/* Encrypt data */
$c_t = mcrypt_generic($td, $string);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
$c_t = $iv.$c_t;
return $c_t;
} //end if
}
function my_decrypt($string,$key) {
$key = md5($key);
/* Encrypt data */
$c_t = mdecrypt_generic($td, $string);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $c_t;
} //end if
}
?>
<?php
24
include("aes_sql.php");
<?php
session_start();
$clean = array();
$email_pattern = '/^[^@\s<&>]+@([-a-z0-9]+\.)+[a-z]{2,}$/i';
if (preg_match($email_pattern, $_POST['email']))
{
$clean['email'] = $_POST['email'];
$user = $_SESSION['user'];
$new_password = md5(uniqid(rand(), TRUE));
if ($_SESSION['verified'])
{
/* Update Password */
mail($clean['email'], 'Your New Password', $new_password);
}
}
?>
<?php
$old_filename = $_FILES['attachment']['tmp_name'];
$new_filename = '/path/to/attachment.txt';
if (move_uploaded_file($old_filename, $new_filename))
{
/* $old_filename is an uploaded file, and the move was successful. */
}
?>
<?php
$filename = $_FILES['attachment']['tmp_name'];
if (is_uploaded_file($filename))
{
26
$size = filesize($filename);
}
?>
<?php
$clean = array();
$html = array();
/* Filter Input ($name, $comment) */
$html['name'] = htmlentities($clean['name'], ENT_QUOTES, 'UTF-8');
$html['comment'] = htmlentities($clean['comment'], ENT_QUOTES, 'UTF-8');
echo "<p>{$html['name']} writes:<br />";
echo "<blockquote>{$html['comment']}</blockquote></p>";
?>
<?php
session_start();
$clean = array();
if (isset($_REQUEST['item'] && isset($_REQUEST['quantity']))
{
/* Filter Input ($_REQUEST['item'], $_REQUEST['quantity']) */
if (buy_item($clean['item'], $clean['quantity']))
{
echo '<p>Thanks for your purchase.</p>';
}
else
{
echo '<p>There was a problem with your order.</p>';
}
}
?>
<?php
session_start();
27
<?php
if (isset($_SESSION['token']) &&
$_POST['token'] == $_SESSION['token'])
{
/* Valid Token */
}
?>
<?php
$token_age = time() - $_SESSION['token_time'];
if ($token_age <= 300)
{
/* Less than five minutes has passed. */
}
?>
- httpd.conf ou .htaccess
Diz-se que não existe robozinho seguro, portanto para aumentar a segurança rejeitando robôs de
instrumentos de busca use no httpd.conf:
robots.txt
User-agent: *
Disallow: /
Quando não temos acesso ao servidor Apache temos a alternativa de usar o script .htaccess no
diretório do aplicativo para melhorar a segurança:
No forum do Joomla podemos encontrar um exemplo deste script muito bom para reforçar a
segurança web de sites:
http://forum.joomla.org/index.php/topic,124708.msg613819.html#msg613819
Original em - http://www.phpnoise.com/tutorials/3/1
// Encrypt string
$output = crypt($string);
// Send to browser
print('Input: ' . $string . "\n");
print('Output: ' . $output);
29
?>
<?php
// Hash string
$hash = 'hash_my_string';
// Encrypt string
$output = crypt($string, $hash);
// Send to browser
print('Input: ' . $string . "\n");
print('Output: ' . $output);
?>
// Send to screen
print('Input: ' . $string . "\n\n");
print('Output: ' . $output . "\n");
print('Output2: ' . $output2 . "\n\n\n");
// Sent to browser
print('Input: ' . $string . "\n\n");
print('Output: ' . $output . "\n");
print('New output: ' . $new_output . "\n\n");
print('Output2: ' . $output2 . "\n");
print('New output2: ' . $new_output2);
?>
30
<?php
?>
<?php
// Get new login information
$new_user_name = trim($_POST['username']);
$new_user_name = stripslashes($_POST['username']);
$new_user_pwd = trim($_POST['password']);
$new_user_pwd = stripslashes($_POST['password']);
$found = true;
break 3;
}
}
}
?>
<?php
?>
Não utilizar...
muita facilidade.
Agora que sabemos algumas coisas que não devem ser utilizadas, vão algumas dicas de boas
senhas:
Utilizar...
• palavras embaralhadas1, que seja somente de seu conhecimento. <li> no mínimo 3 tipos de
caracteres, tais como letras maiúsculas e minúsculas (az e AZ), números (09) e caracteres
especiais (@!#$%&*+=?|<> e outros).
• no mínimo 8 dígitos.
1Consiste em trocar algumas letras da palavra escolhida utilizando as outras dicas, ou seja, escolher
uma palavra e acrescentar ou trocar as letras por números e caracteres especiais, procurando atender
as dicas para criação de uma senha segura.
function verCaracterDaSenha(valor) {
if (erespeciais.test(valor)) cont++;
if (ermaiuscula.test(valor)) cont++;
if (erminuscula.test(valor)) cont++;
if (ernumeros.test(valor)) cont++;
return cont;
}
function segurancaBaixa(d) {
d.innerHTML = '<h4>Seguranca da senha: <font color=\'red\'> BAIXA</font></h4>';
}
function segurancaMedia(d) {
d.innerHTML = '<h4>Seguranca da senha: <font color=\'orange\'> MEDIA</font></h4>';
}
function segurancaAlta(d) {
d.innerHTML = '<h4>Seguranca da senha: <font color=\'green\'> ALTA</font></h4>';
}
function testaSenha(valor) {
var d = document.getElementById('seguranca');
var c = verCaracterDaSenha(valor);
var t = valor.length;
if(t == ''){
d.innerHTML = "<h4>Seguranca da senha: !</h4>";
} else {
if(t > 7 && c >= 3) segurancaAlta(d);
34
else {
if(t > 7 && c >= 2 || t > 4 && c >= 3) segurancaMedia(d);
else segurancaBaixa(d);
}
}
}
// Valid URL
my_form_URL = "http://domain.net/my_form.html";
// Set to lowercase
my_form_URL = strtolower(my_form_URL);
incoming_URL = strtolower($_SERVER['HTTP_REFERER']);
if (my_form_URL == incoming_URL) {
// All ok - continue
} else {
// Someone is cheating!!
echo "Access Denied.";
exit; // stop executing script
}
?>
<body>
<form name="login" method="post"
action="log.php?<?PHP
// generate dynamic_info var
print('data=' . dynamic_info);
?>">
<input type=text name="uName" />
<input type=password name="uPwd" />
<input type=submit value="Submit" />
</form>
</body>
</html>
GET/POST Form trick script
<?PHP
?>
<?php
function clean_it($vName) {
$vName = stripslashes(trim(vName));
$vName = nl2br(vName);
$vName = htmlentities(vName);
return $vName;
}
36
// Usage
$uName = clean_it($_POST['uName']);
?>
<?php
// valid login credentials
$username = 'admin';
$password = 'admin_pass';
// grab current time
$time=time();
// handle login event, both successful and erroneous, or show login screen
if ($login_error == true) { ?>
<table align=center style="font-family:arial; font-size:12; border:1 solid #000000;">
<tr><td align=center bgcolor=#123dd4>LOGIN ERROR</td></tr>
<tr><td align=center><b>Invalid Username and/or Password</b><br><br><a
href=index.php>Back</a></td></tr>
</table>
<?
} elseif ($_COOKIE[user] == md5($username) && $_COOKIE[pass] == md5($password)) { ?>
<table align=center style="font-family:arial; font-size:12; border:1 solid #000000;">
<tr><td align=center bgcolor=#123dd4>SECURE AREA</td></tr>
<tr><td align=right><a href=index.php?logout=true>Logout</a></td></tr>
<tr><td>You have successfully logged in.<br><br>
Encrypted Username: <b><?= $_COOKIE[user] ?></b><br>
Encrypted Password: <b><?= $_COOKIE[pass] ?></b><br>
</td></tr>
</table>
<?
} else {
?>
<form action=index.php method=post>
37
<?php
// Form Autenticação
/* mysql_connect() */
/* mysql_select_db() */
$clean = array();
$mysql = array();
$now = time();
$max = $now - 15;
$salt = 'SHIFLETT';
if (ctype_alnum($_POST['login']))
{
$clean['login'] = $_POST['login'];
}
else
{
/* ... */
}
if ($result = mysql_query($sql))
{
if (mysql_num_rows($result))
{
$record = mysql_fetch_assoc($result);
mysql_query($sql);
}
}
else
{
/* Invalid login */
}
}
else
{
/* Error */
}
</body>
</html>
<?php
//Check a Persistent Login Cookie
/* mysql_connect() */
/* mysql_select_db() */
$clean = array();
$mysql = array();
$now = time();
$salt = 'SHIFLETT';
{
/* ... */
}
$mysql['identifier'] = mysql_real_escape_string($clean['identifier']);
if ($result = mysql_query($sql))
{
if (mysql_num_rows($result))
{
$record = mysql_fetch_assoc($result);
if ($clean['token'] != $record['token'])
{
/* Failed Login (wrong token) */
}
elseif ($now > $record['timeout'])
{
/* Failed Login (timeout) */
}
elseif ($clean['identifier'] !=
md5($salt . md5($record['login'] . $salt)))
{
/* Failed Login (invalid identifier) */
}
else
{
/* Successful Login */
}
}
else
{
/* Failed Login (invalid identifier) */
}
}
else
{
/* Error */
}
?>
</body>
</html>
<?php
40
session_start();
if (isset($_POST['message']))
{
if (isset($_SESSION['token']) && $_POST['token'] == $_SESSION['token'])
{
$message = htmlentities($_POST['message']);
?>
<form method="POST">
<input type="hidden" name="token" value="<?php echo $token; ?>" />
<input type="text" name="message"><br />
<input type="submit">
</form>
<?php
readfile('./messages.txt');
?>
function parsearHTMLInjectado($texto)
{
return nl2br( htmlentities($texto) );
}
Dicas de Segurança
- Nunca enviar valores sigilosos através de inputs tipo hidden, pois podem ser vistos.
- Valide todos os valores antes de usar
- Se não puder validar os valores valide pelo menos os tipos de dados
- Use sempre valores default
- Usar segurança contra spam nos forms, como Captcha.
- Tratar todos os valores de entrada como potencial dano
- Ter sempre um plano para processamento das informações
Usuário super administrador deve ser utilizado somente na instalação e configurações iniciais.
Logo após devemos criar um usuário com menor poder para maior segurança na administração.
Fontes:
Ribamar FS – http://ribafs.net