Motivação

Um cuidado que todo desenvolvedor precisa ter para aprimorar a segurança de aplicações web é a correta utilização dos métodos HTTP. Dessa forma, asseguramos que apenas acessos relacionados ao método especificado tenham “contato” com o servidor e possam trocar informações com ele. Essa proteção é ainda mais importante quando fazemos uso de métodos como POST, PUT e DELETE, geralmente empregados para alterar algum recurso presente no servidor. Nesse artigo, veremos como proteger, por meio de data annotation, os action methods de aplicações ASP.NET MVC, garantindo assim que apenas as requisições dos tipos esperados sejam recebidas pelo servidor.

Método GET: com ou sem annotation

O método GET é o mais comum. Com ele, buscamos informações no servidor e as mostramos para o usuário. Todas as páginas de uma aplicação são exibidas após a execução de requisições do tipo GET. Um link qualquer presente em uma página, por exemplo, irá, obrigatoriamente, realizar uma requisição GET ao servidor.

No caso do ASP.NET MVC, não há necessidade de utilizar uma data annotation específica para os action methods relacionados a esse tipo de requisição. Ainda assim, essa anotação existe e pode ser declarada: [HttpGet]. Atualmente, recomenda-se seu uso apenas por uma questão de legibilidade e compatibilidade com versões anteriores do MVC. O código a seguir mostra um exemplo:


        // GET: Exemplo/Edit/{id}
        [HttpGet] // opcional
        public ActionResult Edit(int id)
        

Do lado do cliente, temos algo extremamente simples, no caso de requisições GET. Como todos os links comuns são requisições desse tipo, o código abaixo é suficiente para chamar o action method Edit(). Note que declaramos um helper do MVC: @Html.ActionLink. Ele irá criar um link na página com os parâmetros passados: texto “Editar”, action method Edit e parâmetro “id = item.Id”.


        @Html.ActionLink("Editar", "Edit", new { id=item.Id })
        

Método POST

O método POST é o mais comum quando há algum tipo de interação do usuário. Em formulários, por exemplo, os dados são enviados ao servidor por meio de um método POST. Isso ocorre devido à natureza do método: diferentemente do GET, o POST possui um corpo (body). Esse corpo da requisição contém os dados, que então são lidos e operados pelo servidor.

É importante citar que o POST é um método genérico: significa, basicamente, que o cliente está enviando informações para o servidor. O que o servidor fará com essas informações fica a critério dele, embora, em geral, o POST seja indicado para a criação de registros.

No caso do MVC, o método POST precisa da anotação [HttpPost]. É essa anotação que vai informar ao Controller que se trata desse método HTTP. Outro ponto importante que podemos notar é que os métodos POST e GET podem ter o mesmo nome, desde que possuam assinaturas diferentes, como mostrado no código abaixo. Anteriormente, vimos o método GET para a view de edição. Agora, temos o POST, recebendo a entidade com os dados que o cliente inseriu.


        // POST: Exemplo/Edit
        [HttpPost]
        public ActionResult Edit(Entity entity)
        

Do lado do cliente, teríamos o código abaixo:


        @using (Html.BeginForm("Edit", "Exemplo", FormMethod.Post))
        

Esse código cria um formulário com a ação “Edit” do controller “Exemplo”. Note que explicitamos que queremos utilizar o método POST, em “FormMethod.Post”; contudo, como por padrão os formulários fazem uso do método POST, esse trecho de código pode ser retirado.

Métodos PUT e DELETE

No caso dos métodos PUT e DELETE, o MVC não possui nenhuma abordagem específica para o lado cliente. Por serem métodos com escopo mais bem definido – o PUT é recomendado para a atualização de dados, e o DELETE, como o nome sugere, para a remoção – eles não são muito empregados em aplicações web. Entretanto, em casos específicos, é importante que saibamos utilizá-los sem causar prejuízo para a aplicação.

Dito isso, saiba que ambos, assim como os métodos POST e GET, possuem anotações: [HttpPut] e [HttpDelete]. Podemos, portanto, declarar métodos com as assinaturas apresentadas na Listagem 1.

Listagem 1. Anotações para PUT e DELETE

        // PUT: Exemplo/Edit
        [HttpPut]
        public ActionResult Edit(Entity entity)
        ...
        <p align="left">05 // DELETE: Exemplo/Edit
        <p align="left">06 [HttpDelete]
        public ActionResult Remove(Entity entity)
        
  • Linha 2: Data annotation que indica que temos um método que utiliza o PUT;
  • Linha 3: Assinatura do action method Edit();
  • Linha 6: Data annotation que indica que temos um método que utiliza o DELETE;
  • Linha 7: Assinatura do action method Remove().

Do lado do cliente, embora não haja uma estrutura específica para garantir que teremos requisições desses tipos, podemos encontrar uma opção. Visto que o FormMethod, por exemplo, é um enum que possui somente dois valores (Get e Post), não podemos utilizá-lo. O MVC, no entanto, possui um helper que serve para “injetar” um método específico no formulário. Vejamos um exemplo na Listagem 2. Note que temos o formulário que irá executar o método HTTP PUT e o outro que tem o método HTTP DELETE.


        @using (Html.BeginForm("Edit", "Exemplo", FormMethod.Post))
        {
        @Html.HttpMethodOverride(HttpVerbs.Put)
        ...
        }
        @using (Html.BeginForm("Remove", "Exemplo", FormMethod.Post))
        {
        @Html.HttpMethodOverride(HttpVerbs.Delete)
        ...
        }
        
  • Linha 1: Definição do formulário para o action method Edit();
  • Linha 3: Declaração do helper HttpMethodOverride(), que irá injetar a informação de que queremos fazer uso do método HTTP PUT. Com esse método, o MVC irá ignorar o “FormMethod.Post” e irá realizar uma requisição PUT ao servidor;
  • Linha 7: Definição do formulário para o action method Remove();
  • Linha 9: Novamente temos o helper HttpMethodOverride(), mas agora injetando a informação de que vamos empregar o método HTTP DELETE;

Por fim, vale reforçar que a correta utilização dos métodos HTTP é bastante importante para controlar o que está acontecendo na aplicação. Portanto, apesar de simples, é sempre interessante relembrar a proposta de cada um:

  • GET: Método genérico para qualquer requisição que busca dados do servidor;
  • POST: Método genérico para qualquer requisição que envia dados ao servidor;
  • PUT: Método específico para atualização de dados no servidor;
  • DELETE: Método específico para remoção de dados no servidor.