Melhore a Segurança dos Aplicativos da Web com o jQuery Mobile

Aprenda a proteger os seus aplicativos remotos

Muitos desenvolvedores da Web consideram a segurança como uma prioridade baixa. Frequentemente, a segurança é relegada ao final do ciclo de vida do desenvolvimento de software, como se fosse apenas algo um pouco mais importante que um assunto de última hora. Às vezes, a segurança de software é totalmente negligenciada, o que tem como resultado aplicativos cheios de vulnerabilidades comuns. Como os erros desse tipo talvez só se manifestem sob as condições presentes durante um ataque, podem ser difíceis de detectar antes desses eventos sem o conhecimento de como o processo de utilização funciona. Usando um aplicativo da Web desenvolvido com jQuery Mobile, PHP e MySQL, este tutorial mostra quantos tipos de vulnerabilidades ocorrem, bem como métodos comuns de utilização e, o que é mais importante, suas respectivas contramedidas.

John Leitch, Application Security Consultant, Freelance

John Leitch é consultor independente de segurança de aplicativos e mora em Grand Rapids, Michigan. Trabalha principalmente com aplicativos da Web e é especialista em teste de imprecisão, análise dinâmica e revisão de código. Sempre à caça de erros, ele lança frequentemente relatórios sobre vulnerabilidade.



04/Jul/2011

Antes de iniciar

Este tutorial se destina a desenvolvedores em jQuery Mobile interessados em proteger os seus aplicativos. Pressupõe que o leitor tem conhecimento básico sobre o desenvolvimento de aplicativos da Web usando PHP, MySQL, JavaScript, XHTML e CSS. Além disso, este tutorial não é completo; destina-se a ser uma introdução à segurança de aplicativos da Web. Para ler mais sobre os temas abordados aqui e outros tópicos relevantes, consulte Recursos.

Acrônimos usados frequentemente

  • API: Application program interface
  • CSRF ou XSRF: Cross-site request forgery
  • CSS: Cascading Stylesheets
  • HTML: Linguagem de Marcação de Hipertexto
  • HTTP: Protocolo de Transporte de Hipertexto
  • OS: Sistema Operacional
  • SQL: Linguagem de Consulta Estruturada
  • URL: Localizador Uniforme de Recursos
  • W3C: World Wide Web Consortium
  • XHTML: Linguagem de Marcação de Hipertexto Extensível
  • XML: Linguagem de Marcação Extensível
  • XSS: Cross-site scripting

Com o surgimento dos smartphones e dispositivos semelhantes, a segurança dos aplicativos da Web foi ampliada para incluir aplicativos remotos. Por causa das limitações impostas pelas interfaces de vários dos dispositivos desse tipo, às vezes os desenvolvedores trabalham com a premissa falsa de que a validação das entradas no lado do cliente é suficiente para a proteção contra ataques. Entretanto, as solicitações enviadas pelos aplicativos remotos podem ser manipuladas da mesma forma que os aplicativos da Web tradicionais. Por causa dessa vulnerabilidade, não é possível confiar no cliente. Com os dados sensíveis às vezes armazenados em dispositivos e nos servidores que eles usam, a proteção dos usuários contra hackers "do mal" é crítica. Este tutorial mostra como vários tipos de vulnerabilidades ocorrem e algumas das contramedidas que podem ser estabelecidas para mitigar os invasores que tentam utilizá-las. Os seguintes tipos de vulnerabilidades são abordados:

  • Scripts de sites cruzados
  • Falsificação de solicitação em sites cruzados
  • Controle de acesso quebrado
  • Injeção de SQL
  • Inclusão de arquivos
  • Injeção de comandos de OS
  • Injeção de linguagem de script
  • Criação de arquivos arbitrários

Todas as vulnerabilidades e contramedidas são demonstradas por meio de um aplicativo de amostra desenvolvido com jQuery Mobile, PHP e MySQL. (Consulte Download para obter um arquivo .zip com o código de amostra.)

Pré-requisitos

Para concluir este tutorial, são necessárias as seguintes ferramentas:

  • Servidor da Web— Pode-se usar qualquer servidor da Web com suporte para PHP. Muitas utilizações deste tutorial são específicas do Windows, mas podem ser adaptadas para outros sistemas operacionais. Sugerimos o servidor da Web Apache ou o IBM HTTPServer.
  • PHP— Já que alguns ataques descritos não funcionam com a versão mais recente, foi usado o PHP 5.3.1. As incompatibilidades desse tipo são indicadas ao longo do tutorial.
  • MySQL— Este tutorial usa o MySQL, um banco de dados de software livre. A versão 5.1.41 foi usada neste tutorial, mas as outras versões podem funcionar bem.
  • Proxy de depuração da Web— Como há necessidade de uma forma de manipular solicitações de HTTP, um proxy de depuração da Web é muito útil. Ao longo deste tutorial, o Fiddler v2.3.2.4 é usado, mas qualquer outro proxy de depuração da Web que permite a modificação de solicitações funciona.
  • jQuery Mobile— O frontend do aplicativo de amostra desenvolvido neste tutorial usa o jQuery Mobile 1.0 Alpha 3.

Consulte Recursos para obter links úteis.


Desenvolvendo um aplicativo sem segurança

Você começa este tutorial criando um aplicativo de exemplo sem segurança, chamado Contrived Mobile Application (CMA), que serve como área de teste para os diversos tipos de ataque abordados nas seções a seguir. Para fazer esse teste, o CMA tem duas partes centrais de funcionalidade:

  • Um sistema de perfil do usuário para customização
  • Uma calculadora para fazer cálculos aritméticos básicos

Cada elemento do aplicativo introduz buracos na segurança que os invasores podem usar para atingir os seus próprios objetivos. Com cada vulnerabilidade coberta, o CMA recebe correções adequadas para tentar impedir a ação de futuros hackers.

O esquema

Como um aplicativo centrado no usuário, o CMA tem um esquema simples, que consiste em uma tabela (consulte a Listagem 1).

Listagem 1. Um trecho do script de instalação do CMA
CREATE TABLE UserAccount
(
Id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
Username VARCHAR(256) NOT NULL,
Password VARCHAR(32) NOT NULL,
    FirstName VARCHAR(256) NOT NULL,
    LastName VARCHAR(256) NOT NULL
);

INSERT INTO UserAccount (Username, Password, FirstName, LastName) 
VALUES ('Jane', md5('Password1'), 'Jane', 'Smith');

INSERT INTO UserAccount (Username, Password, FirstName, LastName) 
VALUES ('John', md5('Password1'), 'John', 'Doe');

São criados dois usuários: Jane e John. Para simplificar as coisas, os níveis de permissão ficaram de fora.

Seleção do idioma

A lógica de seleção do idioma é executada sempre que uma página é carregada (consulte a Listagem 2).

Listagem 2. Tratamento inadequado da entrada passada para require_once
if (isset($_COOKIE['language'])){    require_once($_COOKIE['language'] . ".php");    }

Primeiro, uma instrução condicional verifica se um cookie de idioma está presente. Caso esteja, a extensão PHP é anexada ao valor do cookie e a cadeia de caractere é passada para a função require_once para carregar o script adequado.

Autenticação e autorização

Em seguida, você acrescenta uma proteção rudimentar. Um formulário de login (veja a Figura 1) é criado juntamente com a lógica de autenticação e autorização e, no momento do login bem-sucedido do valor de sessão, CurrentUser é definido como o nome do usuário autenticado. A lógica de autorização é implementada ao verificar esse valor de sessão.

Figura 1. O formulário de login do CMA
O formulário de login do CMA

A Listagem 3 mostra a criação da lógica de autenticação sem segurança.

Listagem 3. Lógica de autenticação sem segurança
<?php

function Authenticate($Username, $Password)
{
    $query = "SELECT COUNT(*) FROM useraccount " . 
        "WHERE Username = '" . $Username . "' AND " . 
        "Password = md5('" . $Password . "');";

    $result = mysql_query($query);

    $_SESSION["CurrentUser"] = $Username;

    return mysql_result($result, 0); 
}

?>

A Listagem 4 mostra a criação da lógica de autorização sem segurança.

Listagem 4. Lógica de autorização sem segurança
<?php

if (!isset($_SESSION["CurrentUser"]) || $_SESSION["CurrentUser"] == NULL)
{
    header("Location: login.php");
}

?>

Busca de usuários

Nenhum aplicativo centrado no usuário está completo sem a capacidade de procurar outros usuários dentro do sistema. O recurso de busca de usuários aceita palavras-chave e retorna as correspondências como uma lista não ordenada (A Figura 2). A Listagem 5 mostra a lógica de busca.

Listagem 5. Tratamento sem segurança de dados enviados pelo usuário na implementação da busca de usuários
Query: <?php echo $query; ?>

<ul data-role="listview" data-theme="c" style="margin-top:12px;">
    <?php

    $query = "SELECT FirstName, LastName " .
        "FROM UserAccount " .
        "WHERE FirstName LIKE '%$query%' OR " .
        "LastName LIKE '%$query%';";

    $result = mysql_query($query) or die(mysql_error());;

    while ($row = mysql_fetch_assoc($result)) {                    
        echo "<li>" . $row["FirstName"] . " " . $row["LastName"] . "</li>";
    }

    ?>
</ul>

A Listagem 5 realiza uma série de funções. Primeiro, realiza a saída da consulta enviada pelo usuário na parte superior da página, como lembrete para os usuários daquilo que foi procurado. Depois disso, as condições de uma instrução SELECT são desenvolvidas dinamicamente a partir das palavras-chave fornecidas pelo usuário. A instrução SQL é passada para mysql_query, e o script faz um loop nos resultados, ecoando dados pertinentes como itens de lista em HTML.

Figura 2. Os resultados de uma busca de usuário
Os resultados de uma busca de usuário

Calculadora

Como os usuários podem precisar resolver problemas aritméticos básicos de imediato, o CMA oferece um recurso de calculadora. A calculadora consiste em três entradas: x, y e operation. A Listagem 6 mostra o código para resolver problemas aritméticos e exibir os resultados.

Listagem 6. Tratamento sem segurança de dados enviados pelo usuário na implementação da calculadora
<?php

$operation = $_GET["operation"] == "operation-add" ?
    "+" : "-";

$arithmetic = "$_GET[x] $operation $_GET[y]";

echo $arithmetic . " = ";

$code = "echo $arithmetic;";

eval($code);

?>

Essa parte do código primeiro verifica os dados de GET para determinar qual operação o usuário selecionou. Em seguida, desenvolve o problema de aritmética como uma cadeia de caractere. Depois, realiza a saída do problema completo, para que o usuário possa vê-lo, antes de interpretar a cadeia de caractere desenvolvida dinamicamente como PHP.

A Figura 3 mostra a calculadora em ação.

Figura 3. A calculadora do CMA fazendo algumas contas
A calculadora do CMA fazendo algumas contas

Agora que você viu a calculadora do CMA, eu tratarei do núcleo do aplicativo: as preferências do usuário.

Preferências do usuário

A capacidade de customizar o CMA de forma pessoal é a sua principal funcionalidade. Permite que os usuários alterem as informações pessoais e façam o upload de uma foto para o seu perfil (consulte a Listagem 7).

Listagem 7. Tratamento sem segurança de dados enviados pelo usuário na implementação das preferências do usuário
<?php

$message = "User preferences have been saved.";

$validated = TRUE;

$update = "UPDATE UserAccount " .
    "SET " .
    "FirstName = '$_REQUEST[firstname]', " .
    "LastName = '$_REQUEST[lastname]' ";
    
$password1 = $_REQUEST["newpassword1"];
$password2 = $_REQUEST["newpassword2"];

if ($password1 != NULL && $password1 != '')
{
    if ($password1 != $password2)
        $validated = FALSE;

    $update .= ", Password = md5('$password1') ";
}

$update .= "WHERE Id = $_REQUEST[userid]";

if ($validated)
    mysql_query($update) or die(mysql_error());

if (isset($_FILES["picture"]))
{
    $image = $_FILES["picture"]["tmp_name"];

    // For this example ping will be used as a mock image
    // compression tool.
    $compress_command = "ping $image $_REQUEST[imagecompression]";

    exec($compress_command);

    move_uploaded_file($image,
        "images/" . $_FILES["picture"]["name"]);
}

echo $message;

?>

O código da Listagem 7 primeiro desenvolve e executa uma instrução UPDATE para a tabela UserAccount. Se o usuário fez o upload de uma imagem, ela é processada com um utilitário de compressão de imagem simulada e, em seguida, é movida para o diretório de imagens.

A Figura 4 mostra a interface de preferências do usuário com os campos First Name, Last Name, New Password, Repeat New Password e Profile Picture.

Figura 4. A interface de preferências do usuário mostrando a conta de John Doe
A interface de preferências do usuário mostrando a conta de John Doe

Depois de tratar da funcionalidade relevante do CMA, está na hora de examinar mais detalhadamente a sua implementação. A próxima seção explica as vulnerabilidades presentes, como alguém pode utilizá-las e o que se pode fazer para impedir esse uso.


Cross-site scripting (XSS)

Um Web site está vulnerável ao XSS quando um hacker pode injetar scripts no lado do cliente para atacar outros usuários. Há dois tipos de XSS: refletido e persistente. É comum a interpretação equivocada de que o XSS não é nada mais que um incômodo. Em alguns casos de XSS refletido, a ameaça é pequena; entretanto, em muitos casos, deixa os usuários vulneráveis ao comprometimento da conta ou algo pior.

XSS refletido

O XSS refletido ocorre quando os dados de solicitação são renderizados sem codificação e sem filtragem na resposta. Com a ajuda da engenharia social, o invasor pode enganar o usuário, fazendo-o visitar uma página que cria uma solicitação desse tipo e permitindo que o invasor execute o JavaScript no contexto do usuário atacado. O que se pode fazer com isso varia de acordo com a natureza do "buraco", mas geralmente o XSS é utilizado para sequestrar sessões, roubar credenciais ou realizar outras ações que, de outra forma, não seriam autorizadas.

Persistente

Geralmente uma ameaça maior que o tipo refletido, uma vulnerabilidade de XSS é considerada persistente quando o servidor salva os dados da solicitação enviados pelo usuário. Já que os dados mal intencionados persistem dentro do aplicativo, o aspecto de engenharia social do ataque se torna mais simples ou é totalmente eliminado, dependendo da utilização.

Utilização

O CMA está cheio de vulnerabilidades de XSS; só a busca de usuários tem os tipos refletido e persistente. A utilização do tipo refletido é mostrada aqui:
http://localhost/CMA/insecure/search.php?query=%3Cscript%3Ealert (document.cookie)%3C/script%3E

Os efeitos do ataque de XSS refletido ficam visíveis imediatamente ao navegar para o link, a não ser que as contramedidas estejam estabelecidas no lado do cliente:
Query: <script>alert(document.cookie)</script>

Recursos contra o XSS podem ser integrados a um navegador, como o Microsoft® Internet Explorer ® 8, ou instalados como um plug-in, como o noXSS para o Firefox. Para os seus fins, os filtros do lado do cliente não devem ser considerados, já que não é possível depender dos usuários para instalá-los e, em muitos casos, eles só protegem contra o tipo refletido. Em alguns casos, a filtragem no lado do cliente é, na verdade, contraproducente, introduzindo vulnerabilidades de universal XSS (UXSS). O Internet Explorer 8 — antes de a Microsoft corrigir a falha — era um exemplo disso.

Para ver o XSS persistente em ação, insira no campo First Name ou Last Name do formulário User Preferences as tags de script mostradas aqui e, em seguida, procure o usuário:
<script>alert(document.cookie)</script>

O JavaScript é executado quando o usuário é mostrado nos resultados da busca.

Impeça os scripts de sites cruzados

Para impedir ataques de XSS, normalmente é necessário aplicar a codificação correta à entrada do usuário na resposta do servidor. No caso do exemplo de XSS refletido da busca de usuários, a aplicação da codificação de entidade HTML deve ser suficiente para impedir ações mal intencionadas. É possível realizar essa etapa com a API de PHP usando a função htmlentities : Query: <?php echo htmlentities($query); ?>.

Agora, o teste do ataque com relação ao código atualizado dá um resultado diferente:
Query: <script>alert(document.cookie)</script>

Agora os caracteres de "menor que" e "maior que" estão codificados como entidades HTML, o que impede que o invasor injete marcação. A vulnerabilidade persistente é corrigida da mesma forma (consulte a Listagem 8) com a função htmlentities .

Listagem 8. Uma modificação no CMA para impedir o XSS persistente
while ($row = mysql_fetch_assoc($result)) 
{					
echo "<li>" . htmlentities($row["FirstName"]) . " " . 
htmlentities($row["LastName"]) . "</li>";					
}

Quando dados enviados pelo usuário forem injetados em um valor de atributo HTML, tome o cuidado de garantir que os delimitadores de cadeia de caractere usados para delimitar o valor sejam retirados ou codificados dentro do valor em si. Do contrário, pode ocorrer injeção de atributo:
<a href='http://www.mywebsite.com/'>My Website</a>

A Listagem 9 mostra como a injeção de atributo pode ocorrer.

Listagem 9. Injeção de atributo possibilitada pela falta de codificação das aspas
<a href='http://www.mywebsite.com/'onmouseover='alert(document.cookie)
'>My Website</a>

Como uma camada a mais de segurança, a habilitação do sinalizador HttpOnly do cabeçalho de resposta Set-Cookie impede que scripts do lado do cliente acessem o cookie protegido. Entretanto, não se pode depender desse recurso, porque alguns navegadores não oferecem suporte total para ele.

A próxima seção trata de outra vulnerabilidade comum que pode ser usada para lançar ataques do lado do cliente contra outros usuários de um sistema.


Cross-site request forgery (CSRF ou XSRF)

O CSRF ocorre quando um invasor engana os usuários e os faz realizar ações dentro de seu contexto de segurança. Se não há medidas de segurança estabelecidas, os hackers conseguem fazer isso, independentemente de o método do formulário ser GET ou POST. Desses dois, os ataques de CSRF que usam o método GET são a maior ameaça, porque a solicitação pode ser falsificada usando apenas uma URL, que o invasor pode usar como origem de uma imagem. Se o ataque tem a capacidade de definir arbitrariamente a origem de uma imagem dentro do sistema, os hackers podem aproveitá-la para lançar um ataque de on-site request forgery (OSRF).

Utilização

Quase todas as ações do CMA podem ser criadas novamente como um ataque de CSRF. A Listagem 10 é um exemplo de ataque baseado em GET que altera a senha do usuário atacado para new_password.

Listagem 10. Exemplo de CSRF para mudança de senha
<html>
    <body>
        <img
src="http://localhost/CMA/insecure/preferences.php?firstname=John&lastname
=Doe&newpassword1=new_password&newpassword2=new_password&userid
=2&imagecompression=5" />
    </body>
</html>

Se o método GET não funcionar, o invasor poderá tentar falsificar a solicitação usando POST (consulte a Listagem 11).

Listagem 11. Exemplo de CSRF para mudança de senha usando o método POST .
<html>
   <body onload="document.forms[0].submit()">
       <form method="POST" action="http://localhost/CMA/insecure/preferences.php">
           <input type="hidden" name="firstname" value="John" />
           <input type="hidden" name="lastname" value="Doe" />
           <input type="hidden" name="newpassword1" value="new_password" />
           <input type="hidden" name="newpassword2" value="new_password" />
           <input type="hidden" name="userid" value="2" />
           <input type="hidden" name="imagecompression" value="5" />
       </form>
   </body>
</html>

O resultado da visualização do HTML renderizado na Listagem 11 é a criação de uma solicitação que é idêntica à de um usuário legítimo que está atualizando as suas preferências, mas todos os valores de formulário são controlados pelo invasor.

Impeça a falsificação de solicitação em sites cruzados

Há duas formas comuns de impedir o CSRF. A forma mais fácil de implementar é verificar o remetente na solicitação de HTTP (consulte a Listagem 12); se a solicitação não vem de uma origem confiável, deve ser rejeitada. Quanto mais granular é a verificação do remetente, melhor é a segurança.

Listagem 12. Uma implementação básica de verificação do remetente
if (strpos($_SERVER["HTTP_REFERER"], $app_host . $app_path) != 0 &&
strpos($_SERVER["HTTP_REFERER"], $app_path) != 0)
die("Invalid request");

Contudo, essa abordagem não é à prova de erros. O uso de um token de segurança é uma contramedida mais segura. Com cada formulário protegido, o servidor inclui um valor de token longo e suficientemente aleatório. Cada valor de token é rastreado no lado do servidor para garantir que seja usado só uma vez e expire depois de um período de tempo predeterminado. No momento do envio do formulário, se o valor está ausente, não é válido ou expirou, a solicitação é rejeitada porque, muito provavelmente é falsa. Sem a capacidade de adivinhar o valor do token, o invasor não consegue realizar o ataque. Se esse mecanismo de segurança é aplicado a todas as páginas do aplicativo, ele também serve para impedir o XSS refletido.

Nas próximas seções, você verá vários tipos de vulnerabilidades do lado do servidor.


Controle de acesso quebrado

Frequentemente, os problemas de controle de acesso são negligenciados porque, na maioria dos casos, o controle de acesso não pode ser testado facilmente por meio de utilitários automatizados. A quebra do controle de acesso do aplicativo ocorre quando usuários não autenticados ou não autorizados podem acessar recursos para os quais não deveriam ter permissão. Esse problema acontece frequentemente quando os desenvolvedores tentam proteger recursos destinados aos usuários autorizados ocultando URLs dos usuários não privilegiados. A pressuposição de que somente isso protege um recurso é falsa; um invasor pode, mesmo assim, descobrir a URL por meio de outros meios, como a inferência. Além disso, os usuários que perdem os privilégios podem, mesmo assim, ser capazes de acessar recursos não autorizados com URLs que eles salvaram.

Utilização

O CMA tem duas vulnerabilidades relacionadas ao controle de acesso: desvio de autenticação e aumento de privilégios. O erro de autenticação vem do ato de não terminar a execução ao descobrir que o usuário não foi autenticado. A tentativa de realizar uma ação proibida (consulte a Listagem 13) em um navegador tem como resultado um comportamento aparentemente esperado: o navegador é redirecionado para a página de login.

Listagem 13. Uma solicitação não autenticada referente a recursos privilegiados
POST http://localhost/CMA/insecure/preferences.php HTTP/1.1
Host: localhost
Connection: keep-alive
Content-Length: 107
Cache-Control: max-age=0
Origin: null
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.16 
  (KHTML, like Gecko) Chrome/10.0.648.151 Safari/534.16
Content-Type: application/x-www-form-urlencoded
Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8
  ,image/png,*/*;q=0.5
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

firstname=John&lastname=Doe&newpassword1=new_password&newpassword2
=new_password&userid=2&imagecompression=5

Como a Listagem 14 mostra, a análise do tráfego com um proxy de depurador da Web, como o Fiddler, revela que há muito mais coisas acontecendo:

Listagem 14. Um trecho da resposta que mostra que o intérprete não terminou a execução adequadamente
HTTP/1.1 302 Found
Date: Sat, 19 Mar 2011 23:14:44 GMT
Server: Apache/2.2.14 (Win32) DAV/2 mod_ssl/2.2.14 OpenSSL/0.9.8l 
 mod_autoindex_color PHP/5.3.1 mod_apreq2-20090110/2.7.1 mod_perl/2.0.4 Perl/v5.10.1
X-Powered-By: PHP/5.3.1
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Location: login.php
Content-Length: 1138
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
...

Embora o servidor tenha respondido com um código de status 302, o corpo da resposta contém tudo o que um usuário autenticado recebe. Além disso, a mudança de senha foi bem-sucedida e a conta atacada foi comprometida.

Além da vulnerabilidade de desvio da autenticação, o CMA contém outro problema de controle de acesso: o aumento de privilégios. Sempre que um usuário atualiza o seu perfil, o Id da conta do usuário — armazenado em um campo oculto do formulário, como se mostra aqui — é enviado juntamente com o formulário:
<input type="hidden" name="userid" id="userid" value="2" />

Quando o formulário é postado de volta no servidor, não é realizada nenhuma validação para confirmar que o Id enviado é o do usuário atual real, antes do uso do valor para carregar o registro a partir do banco de dados. Um usuário mal intencionado pode usar ferramentas de desenvolvimento da Web baseadas em navegador para alterar o valor do campo oculto antes de enviar o formulário ou alterar a solicitação usando um proxy de depuração da Web para especificar um Id arbitrário, permitindo que o usuário mal intencionado faça alterações em contas de usuário que não são dele.

Impeça a quebra do controle de acesso

Para impedir o desvio de autenticação, certifique-se de que a execução da lógica do seu aplicativo protegido não ocorra se a verificação autenticação ou autorização falhar. No PHP, é importante lembrar que a definição do campo Location da resposta usando a função de cabeçalho não termina a execução. A Listagem 15 mostra o código de autorização que faz isso adequadamente.

Listagem 15. Código de autorização melhorado
<?php

if (!isset($_SESSION["CurrentUser"]) || $_SESSION["CurrentUser"] == NULL)
{
    header("Location: login.php");

    exit;
}

?>

Caso se determine que o usuário não está autorizado, a função exit é chamada depois que o cabeçalho Location é definido. Essa etapa impede a execução do restante do script.

Para eliminar o aumento de privilégios, certifique-se de que a autorização adequada seja executada para todas as ações privilegiadas. Evite armazenar dados no lado do cliente quando podem ser armazenados no lado do servidor. O ID do usuário na Listagem 15 é um bom exemplo de dados que podem ser armazenados na sessão. Parte da correção é mostrada aqui:
$update .= "WHERE Id = $_SESSION[userid]";

A próxima é a injeção de SQL, uma vulnerabilidade bastante conhecida com uma ampla variedade de consequências possíveis.


Injeção de SQL

Apesar de ser cada vez mais conhecida, a injeção de SQL continua sendo um problema. As consequências de uma injeção de SQL bem-sucedida variam de acordo com a vulnerabilidade. Estas são algumas das ameaças que podem ser introduzidas:

  • Divulgação de dados
  • Modificação dos dados já existentes
  • Inserção de novos dados
  • Acesso arbitrário ao sistema de arquivos
  • Acesso arbitrário à rede
  • Comprometimento do sistema

Utilização

Todas as consultas no CMA são vulneráveis à injeção de SQL — portanto, você trabalhará com vários vetores de entrada. Ao injetar uma condição e colocar comentários no restante da consulta por meio da autenticação de nome de usuário, pode-se desviar da autenticação. A Listagem 16 mostra a consulta da forma que deveria ser.

Listagem 16. A instrução select quando John e Password1 são enviados como credenciais de usuário
SELECT COUNT(*) FROM UserAccount 
WHERE Username = 'John' AND  Password = md5('Password1');

A Listagem 17 mostra como fica a instrução quando uma cadeia de caractere mal intencionada é usada para injetar código na primeira condição.

Listagem 17. Uma instrução select quando 'or 1=1;# e uma senha vazia são enviados como credenciais
SELECT COUNT(*) FROM UserAccount 
WHERE Username = ''or 1=1;#' AND  Password = md5('');

Como 1 é sempre igual a 1 e a condição de verificação de senha é comentada pelo caractere de sustenido (#), a consulta da Listagem 17 retorna a contagem de todos os registros da tabela UserAccount. Se a contagem não é zero, o valor de retorno da função Authenticate é avaliado como true, dando acesso ao invasor.

A funcionalidade de busca de usuários é vulnerável de uma forma que pode ser utilizada para extrair dados arbitrários, entre outras coisas. A Listagem 18 mostra a consulta de busca da forma que ela deveria funcionar.

Listagem 18. A consulta de busca de usuários sob condições normais
SELECT FirstName, LastName FROM UserAccount 
WHERE FirstName LIKE '%John%' OR LastName LIKE '%John%';

Usando o operador UNION, os invasores podem anexar uma consulta totalmente nova para recuperar os dados que eles escolherem:
'and 1=0 UNION SELECT Username, Password FROM UserAccount;#

A Listagem 19 mostra a consulta gerada dinamicamente depois do envio da cadeia de caractere de ataque.

Listagem 19. A consulta de busca de usuários depois da injeção de SQL
SELECT FirstName, LastName FROM UserAccount 
WHERE FirstName LIKE '%'and 1=0 UNION SELECT Username, 
Password FROM UserAccount;#%' OR LastName LIKE '%'and 1=0 
UNION SELECT Username, Password FROM UserAccount;#'";

O ataque dá o resumo dos nomes de usuário e senha de todos os usuários do banco de dados (veja a Figura 5).

Figura 5. O resultado de uma injeção bem-sucedida usando o operador UNION
O resultado de uma injeção bem-sucedida usando o operador UNION

Impeça a injeção de SQL

Para impedir a injeção de SQL, você deve escapar e validar adequadamente todas as entradas enviadas pelo usuário. A maioria das APIs de desenvolvimento da Web vem com funções para fazer isso. No PHP e MySQL, use consultas parametrizadas juntamente com mysql_real_escape_string para os valores de cadeia de caractere, para proteger contra vários ataques (consulte a Listagem 20).

Listagem 20. Código de autenticação atualizado utilizando as medidas preventivas oferecidas pela API do PHP
$query = sprintf("SELECT COUNT(*) FROM useraccount " . 
    "WHERE Username = '%s' AND " . 
    "Password = md5('%s');",
    mysql_real_escape_string($Username),
    mysql_real_escape_string($Password));

Como a Listagem 21 mostra, o desvio da autenticação não funciona mais devido ao escape do delimitador no início da cadeia de caractere de ataque.

Listagem 21. Uma tentativa de injeção com a nova correção estabelecida
SELECT COUNT(*) FROM useraccount 
WHERE Username = '\'or 1=1;#' AND Password = md5('');

É importante usar o especificador de tipo correto na cadeia de caractere de formato. A conversão para o tipo esperado fornece uma camada adicional de proteção (consulte a Listagem 22).

Listagem 22. Criando uma consulta com segurança por meio de um inteiro não confiável
$query = sprintf("SELECT * FROM useraccount WHERE Id = %d", (int)$_GET['id']);

A seção subsequente trata da inclusão de arquivos, um tipo de erro que é comum em aplicativos da Web em PHP.


Inclusão de arquivos

Há dois tipos de inclusão de arquivos: remota e local. Como o próprio nome indica, esse tipo de vulnerabilidade permite que o invasor inclua um arquivo arbitrariamente. O resultado pode ser a divulgação do conteúdo do arquivo ou a execução como código, dependendo da natureza da utilização. No PHP, a inclusão de arquivos remotos geralmente não é possível se allow_url_fopen está desabilitado no arquivo php.ini.

Utilização

O cookie de idioma no CMA é vulnerável à inclusão de arquivo local e, se o servidor está configurado para permitir a abertura de URLs, à inclusão de arquivos remotos. Ao passar uma série de sequências de travessias juntamente com uma pasta e um arquivo fora da webroot, seguidas por um byte nulo para terminar a cadeia de caractere, é possível incluir arquivos arbitrários. A Listagem 23 mostra uma solicitação mal intencionada que inclui o arquivo win.ini.

Listagem 23. Uma solicitação mal intencionada que tenta recuperar o arquivo win.ini do servidor
GET http://localhost/cma/insecure/index.php HTTP/1.1
Host: localhost
Connection: keep-alive
Referer: http://localhost/cma/insecure/index.html
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.16 (KHTML,
  like Gecko) Chrome/10.0.648.151 Safari/534.16
Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,
  image/png,*/*;q=0.5
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie: language=..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fwindows%2fwin.ini%00

A Listagem 24 mostra a resposta do servidor.

Listagem 24. A resposta do servidor, que mostra um ataque bem-sucedido
HTTP/1.1 200 OK
Date: Sun, 20 Mar 2011 20:59:41 GMT
Server: Apache/2.2.14 (Win32) DAV/2 mod_ssl/2.2.14 OpenSSL/0.9.8l 
mod_autoindex_color PHP/5.3.1 mod_apreq2-20090110/2.7.1 mod_perl/2.0.4 Perl/v5.10.1
X-Powered-By: PHP/5.3.1
Set-Cookie: PHPSESSID=39q2aarl86t01j697vrb6ekjf2; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 6142
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html

; for 16-bit app support
[fonts]
[extensions]
[mci extensions]
[files]
[Mail]
MAPI=1
[MCI Extensions.BAK]
m2v=MPEGVideo
mod=MPEGVideo
[Trimmed]

Observe que o byte nulo que envenenava os caminhos não funciona mais no PHP 5.3.4. Entretanto, em alguns casos, ele não é necessário — portanto, não considere isso, isoladamente, como a correção das vulnerabilidades de inclusão de arquivos.

Além da divulgação de arquivos arbitrários, às vezes a inclusão de arquivos pode ser usada para enganar o servidor, fazendo-o interpretar tipos de arquivo arbitrários (como jpgs) como código.

Impeça a inclusão de arquivos

Se possível, evite passar a entrada do usuário para qualquer tipo de função que leia ou inclua arquivos. Se não for possível evitar essa abordagem, tente adotar a abordagem de lista branca à validação dos dados, como se faz na A Listagem 25. Se o número de valores válidos for alto demais para uma lista branca, verifique se há sequências de travessia ou bytes nulos e rejeite a solicitação (não tente higienizá-la). Certifique-se de que o servidor anexe a extensão do nome de arquivo enviado pelo usuário.

Listagem 25. Código atualizado de seleção de idioma que bloqueia ataques de inclusão de arquivos
$languages = array(    "en-us",    "en-ca");if (isset($_COOKIE['language']))
{    if (in_array($_COOKIE['language'], $languages)     
require_once($_COOKIE['language'] . ".php");
else
die("Invalid language.");}

Como o código atualizado só permite os valores de cookie contidos no array de idiomas, os usuários não conseguem mais utilizar a funcionalidade de seleção de idioma para incluir arquivos arbitrários.

Embora a inclusão de arquivos locais seja uma ameaça séria, as consequências do ataque descrito nas seções a seguir podem ser ainda mais graves.


Injeção de comandos de OS

Como é de se esperar, a injeção de comandos de OS é uma ameaça muito séria. Se a entrada do usuário é passada para uma função que executa comandos do sistema operacional, tome o cuidado de garantir que o escape dos dados seja adequado.

Utilização

A compressão da imagem simulada da funcionalidade de preferências do usuário é vulnerável à injeção de comandos de OS. É possível injetar comandos passando o caractere de barra vertical (|) seguido por um comando mal intencionado usando os dados de compressão de imagem no corpo da solicitação (consulte a Listagem 26).

Listagem 26. O corpo de uma solicitação mal intencionada
------WebKitFormBoundaryFnGBYVe08wA8NMrs
Content-Disposition: form-data; name="firstname"

John
------WebKitFormBoundaryFnGBYVe08wA8NMrs
Content-Disposition: form-data; name="lastname"

Doe
------WebKitFormBoundaryFnGBYVe08wA8NMrs
Content-Disposition: form-data; name="newpassword1"


------WebKitFormBoundaryFnGBYVe08wA8NMrs
Content-Disposition: form-data; name="newpassword2"


------WebKitFormBoundaryFnGBYVe08wA8NMrs
Content-Disposition: form-data; name="picture"; filename="x.txt"
Content-Type: text/plain


------WebKitFormBoundaryFnGBYVe08wA8NMrs
Content-Disposition: form-data; name="userid"

2
------WebKitFormBoundaryFnGBYVe08wA8NMrs
Content-Disposition: form-data; name="imagecompression"

5|calc
------WebKitFormBoundaryFnGBYVe08wA8NMrs-

O valor passado para a função do sistema é mostrado aqui:
ping "C:\tools\xampp\tmp\php7533.tmp" 5|calc

Impeça a injeção de comandos de OS

Evite passar a entrada do usuário para funções que executam comandos de OS. Geralmente é possível usar funções de API mais seguras para obter um resultado semelhante. Se não é possível adotar uma abordagem mais segura e há necessidade de usar dados não confiáveis para criar argumentos de linha de comando, certifique-se de que o escape dos dados seja realizado adequadamente. A API do PHP fornece uma função para realizar o escape de caracteres perigosos, chamada escapeshellcmd. A Listagem 27 mostra o código corrigido de preferência do usuário.

Listagem 27. Uso de escapeshellcmd para "limpar" a entrada do usuário
$compress_command = "ping $image " .
    escapeshellcmd($_REQUEST["imagecompression"]);

Ao passar a entrada de usuário para escapeshellcmd antes de passá-la para o sistema, caracteres mal intencionados — como a barra vertical — podem ser higienizados.

A próxima vulnerabilidade frequentemente tem um resultado semelhante ao da injeção de comandos de OS.


Injeção de linguagem de script

A vulnerabilidade de injeção de linguagem de script está presente quando a entrada do usuário é interpretada como código. Em muitos casos, isso leva ao comprometimento do servidor, já que o invasor consegue executar o código dentro do contexto de segurança do processo do intérprete.

Utilização

Já que os dados enviados pelo usuário são passados para a função eval , a funcionalidade da calculadora do CMA é vulnerável à injeção de linguagem de script. As entradas X e Y podem ser usadas para executar um código arbitrário mas, como são do tipo número, é necessário desviar das restrições no lado do cliente. Esse desvio pode ser realizado por meio de um proxy de depuração da Web:

/CMA/insecure/calculator.php?x=1&y=1;system(%22calc%22)&operation=operation-add

Ou pela criação manual da cadeia de caractere de consulta:

/CMA/insecure/calculator.php?x=1;system(%22calc%22);//&y=1&operation=operation-add

Os efeitos dos ataques de injeção de script sobre o código avaliado são:
echo 1 + 1;system("calc"); e aqui: echo 1;system("calc");// + 1;

Impeça a injeção de linguagem de script

Evite avaliar a entrada do usuário como entrada. Geralmente, pode-se criar uma funcionalidade relevante usando funções de API mais seguras (essa é a abordagem adotada na Listagem 28). Se não for possível evitar isso, aplique uma validação rigorosa (se possível, lista branca) e rejeite qualquer entrada que não seja considerada segura. Não tente higienizar a entrada do usuário.

Listagem 28. Lógica da calculadora reescrita
<?php

$x = $_GET["x"];
$y = $_GET["y"];

$operation = $_GET["operation"] == "operation-add" ?
    "+" : "-";
    
// Patched reflected XSS vulnerability
$arithmetic = htmlentities("$x $operation $y");

echo $arithmetic . " = ";

if ($operation == "+")
    echo $x + $y;
else
    echo $x - $y;

?>

Como eval é evitado no código atualizado, o código está protegido contra a injeção de linguagem de script.

A próxima seção explica como a criação de arquivos arbitrários pode ser utilizada para produzir um efeito semelhante.


Criação de arquivos arbitrários

Em muitos casos, o resultado da criação de arquivos arbitrários é semelhante ao da injeção de linguagem de script; um invasor pode criar um arquivo com a extensão adequada e, em seguida, acessá-lo para executar o código arbitrário. O invasor pode fazer isso de várias formas, e você deve ter cuidado ao trabalhar com qualquer funcionalidade que possa ser aproveitada para criar arquivos. Em algumas situações, essa funcionalidade pode ser combinada a outras vulnerabilidades, como a travessia de diretórios, permitindo que o invasor cause mais danos.

Utilização

Uma forma de criar um arquivo arbitrário é usar o recurso de upload de foto de perfil das preferências do usuário para fazer o upload de um arquivo PHP e não uma imagem. Um script simples pode fornecer um shell remoto:
<?php system($_GET["CMD"]); ?>.
Depois do upload, um invasor pode acessar o script para executar comandos do OS com facilidade:
http://localhost/CMA/insecure/images/shell.php?CMD=calc

Dependendo da presença (ou não) de uma vulnerabilidade adequada de injeção SQL e da configuração do servidor, pode haver a possibilidade de aproveitar o SQL para criar um novo script. Dependendo das permissões do SQL server, pode ser possível utilizar a travessia de diretórios para sobrescrever arquivos críticos de sistema, comprometendo efetivamente o servidor:
SELECT '<?php system($_GET["CMD"]); ?>' FROM dual INTO OUTFILE '../../htdocs/shell.php'

A primeira coluna da consulta deve parecer familiar; na verdade, é um literal de cadeia de caractere que contém o arquivo mal intencionado em Criação de arquivos arbitrários (consulte a Listagem 29).

Listagem 29. O shell que cria consulta injetado no CMA usando o operador UNION
http://localhost/CMA/insecure/search.php?query='and%201=0%20UNION%20SELECT
%20'%3C?php%20system($_GET[%22CMD%22]);%20?%3E',''%20FROM%20dual%20INTO%20OUTFILE
%20'../../htdocs/shell.php';%23

É possível descobrir caminhos que podem ser alvo desse tipo de ataque por meio de tentativa e erro ou aproveitando uma vulnerabilidade de vazamento de informações (não abordada neste tutorial) que revela o caminho absoluto da raiz do documento.

Impeça a criação de arquivos arbitrários

Se possível, realize a validação de lista branca nas extensões de quaisquer arquivos que os usuários possam criar. Essa abordagem é a abordagem usada para corrigir o CMA, mostrada na Listagem 30 e na Listagem 31. Se não for possível implementar uma correção semelhante, use a validação de lista negra para garantir que não sejam permitidas extensões mal intencionadas. Para o Apache e o PHP, essa abordagem significa rejeitar várias extensões, como PHP, PHTML e HTACCESS. Se a entrada é considerada mal intencionada, rejeite-a; não tente higienizar dados questionáveis.

Listagem 30. Uma função de ajuda usada para procurar o envenenamento por byte nulo
function IsNullPoisoned($string)
{
    return strpos($string, "\x00") != NULL;    
}

function IsValidImageExtension($file)
{
    $validExtensions = array(
        "jpg",
        "png",
        "gif"
    );
    
    if (IsNullPoisoned($file))            
        return FALSE;

    $ext = pathinfo($file, PATHINFO_EXTENSION);
    
    return in_array($ext, $validExtensions);        
}

A função IsNullPoisoned verifica a cadeia de caractere procurando bytes nulos e retorna true se a posição não é nula, ao passo que a função IsValidImageExtension verifica para garantir que o nome de arquivo não esteja envenenado por nulo e que a sua extensão esteja na lista branca.

Listagem 31. A funcionalidade de foto do usuário do CMA com a validação da extensão de arquivos incluída
if (!IsValidImageExtension($_FILES["picture"]["name"]))
    die("Error uploading image.");

Para impedir ataques, o nome do arquivo enviado pelo usuário é passado para a função IsValidImageExtension e, caso retorne false, o script é terminado.

No PHP, eu recomendo evitar filtros de extensão baseados em expressões regulares. A Listagem 32 mostra uma função de validação da qual se pode desviar.

Listagem 32. Validação de extensão sem segurança
function IsValidImageExtension($file)
{
    return preg_match('/\.(jpg|png|gif)$/i', $file);    
}

A implementação na Listagem 32 impede alguns ataques, mas a função preg_match pode ser suscetível ao envenenamento por byte nulo: test.php%00test.jpg.

Como a Listagem 33 mostra contramedidas para isso mas, devido à maior complexidade, evite esse caminho.

Listagem 33. Validação baseada em expressão regular corrigida
function IsValidImageExtension($file)
 {
     return !IsNullPoisoned($file) && preg_match('/\.(jpg|png|gif)$/i', $file);
 }

Verifique o nome do arquivo em relação ao envenenamento por byte nulo antes de usar preg_match para impedir que o invasor injete o caractere de término de cadeia de caractere.

Certifique-se de que todas as vulnerabilidades de injeção de SQL sejam corrigidas para impedir que os invasores usem a funcionalidade de servidor de banco de dados para manipular o sistema de arquivos. Se o aplicativo não precisa dessa funcionalidade, considere a possibilidade de desabilitar os recursos que usam privilégios de banco de dados. Se possível, execute o servidor de banco de dados em um servidor separado do servidor de HTTP.

Para ter uma camada extra de segurança, armazene arquivos carregados pelo usuário fora da raiz do documento ou proíba o acesso para os usuários usando recursos do servidor da Web caso o acesso direto seja desnecessário. Se um invasor consegue se desviar dos filtros de extensão de arquivo, essa abordagem dificulta o acesso e a execução do script mal intencionado. Não dê ao cliente o controle da pasta de destino de upload; do contrário, um invasor pode usar a travessia de diretório (abordada anteriormente neste tutorial) para armazenar o arquivo em um diretório sem proteção.


Resumo

Como já foi mencionado, este tutorial não é completo. Na verdade, não existe nenhuma fonte completa, devido às constantes mudanças no panorama da segurança de software. A melhor proteção contra invasores em constante evolução é permanecer atualizado, lendo regularmente sobre novas ameaças à segurança. Para ver várias fontes excelentes que examinam com profundidade o motivo das vulnerabilidades e o que pode ser feito para evitá-las, consulte Recursos. Lembre-se: da mesma forma que não é possível dizer que um sistema está livre de erros, não é possível considerá-lo totalmente seguro.


Download

DescriçãoNomeTamanho
Tutorial source codeCMA-Source.zip9KB

Recursos

Aprender

  • Trabalhando com jQuery (Michael Abernethy, developerWorks, setembro de 2008): conheça o jQuery e aprenda a implementá-lo nos seus próprios projetos de aplicativos da Web com esta boa introdução à estrutura JavaScript.
  • Introduction to jQuery Mobile (C. Enrique Ortiz, developerWorks, fevereiro de 2011): encontre mais informações sobre o desenvolvimento com jQuery Mobile.
  • Locking down your PHP applications (Thomas Myer, developerWorks, maio de 2006): saiba mais sobre a proteção dos seus aplicativos de PHP e proteja-se contra as ameaças mais comuns à segurança: injeções de SQL, manipulação das variáveis GET e POST, ataques de estouro de buffer, ataques de script de sites cruzados, manipulação de dados dentro do navegador e postagem de formulários remotos.
  • Sete Hábitos para Escrever Aplicativos PHP Seguros (Nathan Good, developerWorks, setembro de 2008): aumente a segurança do seu aplicativo da Web com outro bom artigo sobre a melhora da segurança dos aplicativos em PHP.
  • Overcome security threats for Ajax applications (Sachiko Yoshihama, Frederik De Keukelaere, Michael Steiner, Naohiko Uramoto; developerWorks, junho de 2007): saiba mais sobre ataques no lado do cliente e como evitar alguns dos ataques mais comuns.
  • Packet Storm: explore uma fonte excelente de utilizações, relatórios e ferramentas antigas e novas.
  • The Web Application Hacker's Handbook (Dafydd Stuttard and Marcus Pinto, Wiley, outubro de 2007): obtenha uma visão mais ampla da segurança dos aplicativos da Web com esse guia prático para encontrar e utilizar falhas na segurança.
  • O Open Web Application Security Project (OWASP): encontre várias informações relevantes e ferramentas para melhorar a segurança do software de aplicativo.
  • Common Vulnerabilities and Exposures (CVE): explore uma boa fonte de informações sobre vulnerabilidades e exposições da segurança conhecidas publicamente.
  • O Open Source Vulnerability Database: examine oura fonte pública de informações sobre vulnerabilidade semelhante ao CVE.
  • jQuery Mobile: visite a página inicial de um sistema unificado de interface do usuário em todas as plataformas bastante difundidas de dispositivos remotos, desenvolvido sobre a base firme do jQuery e jQuery UI.
  • jQuery Mobile: demos e documentação: acesse artigos, APIs, e código de demo para essa estrutura da Web otimizada para toque, para smartphones e tablets.
  • jQuery.org: visite a página inicial da equipe de software livre do jQuery.
  • Mobile Design and Development (Brian Fling, O'Reilly Media, agosto de 2009): explore diretrizes práticas, padrões, técnicas e boas práticas para desenvolver produtos remotos.
  • Área de XML do developerWorks: Obtenha os recursos necessários para melhorar suas qualificações na esfera de XML.
  • Zona de software livre do developerWorks: Encontre amplas informações práticas, ferramentas e atualizações de projeto para ajudá-lo no desenvolvimento de tecnologias de software livre, e use-as com produtos da IBM, bem como nossos mais populares artigos e tutoriais.
  • Certificação XML da IBM: Descubra como se tornar um Desenvolvedor Certificado pela IBM em XML e tecnologias relacionadas.
  • Biblioteca técnica de XML: Consulte a zona de XML para obter uma ampla gama de artigos técnicos e dicas, tutoriais, padrões e Redbooks da IBM. Leia também mais dicas de XML.
  • eventos técnicos e webcasts do developerWorks: Mantenha-se atualizado em relação à tecnologia nessas sessões.
  • DeveloperWorks no Twitter: Inscreva-se hoje para seguir os tweets do developerWorks.
  • Podcasts do developerWorks: Ouça entrevistas e discussões interessantes para desenvolvedores de software.
  • Demos on demand do developerWorks: Acompanhe demos que abrangem desde a instalação de produto e configuração para iniciantes até funcionalidade avançada para desenvolvedores experientes.

Obter produtos e tecnologias

  • O jQuery Mobile CDN: obtenha o jQuery Mobile rapidamente com versões já reduzidas e comprimidas do jQuery Mobile.
  • MAMP: Mac - Apache - MySQL - PHP: obtenha e instale um ambiente de servidor local do Apache, MySQL & PHP baseado em Mac.
  • XAMPP: obtenha um Apache Distribution para Linux®, Solaris, Windows e Mac OS X. O pacote inclui o Apache Web Server, MySQL, PHP, Perl, um servidor de FTP e phpMyAdmin.
  • Fiddler: faça o download e experimente um proxy de depuração na Web que registra todo o tráfego de HTTP(S) entre o seu computador e a Internet.
  • Versões de avaliação de produtos IBM : Faça o download ou explore as versões de teste on-line no IBM SOA Sandbox e entre em contato com as ferramentas de desenvolvimento de aplicativos e produtos de middleware do DB2 ®, Lotus®, Rational®, Tivoli®e WebSphere®.

Discutir

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Software livre
ArticleID=697169
ArticleTitle=Melhore a Segurança dos Aplicativos da Web com o jQuery Mobile
publish-date=07042011