Dicas de codificação segura em C#
Tags: appsec, security, csharp, dotnet
Published: 2023-11-07 14:26:43

Você sabia que C# está entre as 4 linguagens de programação mais populares no mundo, segundo dados do [Programming Language Index](https://pypl.github.io/PYPL.html)? Se você é uma pessoa desenvolvedora em C#, é bem provável que tenha interesse em aperfeiçoar suas práticas nessa linguagem, inclusive no que tange à segurança de aplicações, tema que está cada vez mais em alta à medida que aumenta os casos de crimes cibernéticos.

C# é uma das linguagens de programação que fazem parte do .NET, que é uma plataforma para desenvolvimento de software da [Microsoft](https://learn.microsoft.com/pt-br/training/). O .NET fornece um ambiente de execução, uma biblioteca de classes e vários serviços que facilitam o trabalho dos desenvolvedores. Esses recursos são fáceis de usar, versáteis e poderosos. Você pode usar C# e .NET para criar vários tipos de aplicações: desktop, web e jogos.

Mas essas tecnologias também têm seus riscos. A maioria das aplicações dessa linguagem pode simplesmente usar a infraestrutura implementada pelo .NET. Em alguns casos, é necessária segurança adicional e específica da aplicação. Por isso, **desenvolvimento seguro em C# significa seguir algumas práticas recomendadas que evitam introduzir vulnerabilidades de segurança mais comuns no software**.

Neste artigo, iremos apresentar algumas das práticas e princípios que a [OWASP (Open Worldwide Application Security Project)](https://owasp.org/) e a Microsoft recomendam para desenvolvedores. Seguindo essas dicas, você vai proteger sua aplicação contra algumas ameaças de segurança e agregar valor e qualidade ao seu código.


## Estude os padrões, estruturas e frameworks da linguagem
A segurança no mundo do C# geralmente está relacionada ao .NET Framework. De tal forma, uma das vantagens de trabalhar com um framework sólido é que ele oferece padrões eficazes que ajudam a manter as aplicações seguros.

Com o ASP.NET Core 7.0, o framework tornou-se ainda mais robusto. Como desenvolvedor, é importante que você compreenda esses padrões e saiba como garantir que eles não sejam comprometidos.

Dessa forma, **a segurança de suas aplicações web com ASP.NET Core depende de vários fatores e práticas a serem considerados e implementados**. Algumas recomendações importantes de segurança destacadas pela documentação que você precisa conhecer são:


- [Usar autenticação e autorização baseadas em tokens:](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/best-practices?view=aspnetcore-7.0) o processo de verificar a identidade de um usuário, enquanto autorização é o processo de verificar as permissões de um usuário. ASP.NET Core oferece vários mecanismos para implementar autenticação e autorização nas suas aplicações web, como o Identity, que é um sistema integrado para gerenciar usuários, senhas, perfis e funções.

- [Usar limitação de taxa:](https://www.infoworld.com/article/3705948/how-to-improve-api-security-in-aspnet-core.html) uma técnica para controlar o número de requisições que um cliente pode fazer aos seus serviços em um determinado período de tempo.

- [Utilizar mecanismo CORS (Cross-Origin Resource Sharing)](https://learn.microsoft.com/en-us/dotnet/standard/security/secure-coding-guidelines): um mecanismo que permite ou bloqueia requisições de origens diferentes do seu domínio.

- [Usar técnicas de registro e monitoramento:](https://learn.microsoft.com/en-us/dotnet/core/extensions/logging?tabs=command-line) são técnicas para acompanhar as atividades e os eventos dos seus serviços e detectar possíveis problemas ou ameaças à segurança.

Em resumo, é fundamental realizar uma pesquisa aprofundada sobre o framework, seus principais recursos e as ferramentas que você está utilizando na aplicação. Vale lembrar que essas práticas não são as únicas e nem as definitivas, mas são um bom ponto de partida para você começar a entender sobre a profundidade da segurança de suas aplicações.


## Mantenha seu framework, bibliotecas e pacotes de terceiros atualizados
O framework e as bibliotecas que você utiliza no seu código são essenciais para o funcionamento e a qualidade do seu software. Mas eles também podem ser alvos de ataques cibernéticos, principalmente se não forem verificados e atualizados com frequência. 

Para evitar isso, você deve **manter suas bibliotecas sempre atualizadas com as versões mais recentes**. Isso vai garantir que você tenha os recursos, as correções e as melhorias de segurança atualizadas. Ademais, isso evitará problemas de compatibilidade ou desempenho que podem ocorrer com versões desatualizadas.

Uma forma fácil e prática de atualizar o seu framework e as suas bibliotecas é usar o [NuGet](https://learn.microsoft.com/pt-br/dotnet/csharp/versioning), um gerenciador de pacotes para .NET. O NuGet permite que você instale, remova e atualize os pacotes utilizados em sua aplicação.

Além disso, você pode usar uma ferramenta [SCA (Software Composition Analysis)](https://owasp.org/www-community/Source_Code_Analysis_Tools) para complementar o NuGet na atualização do seu framework e das suas bibliotecas. **Uma ferramenta SCA pode verificar se os pacotes que você usa estão atualizados**, se eles têm alguma vulnerabilidade conhecida, se eles são compatíveis com as licenças do seu projeto e se eles têm alguma dependência transitiva que você não conhece

## Siga as boas práticas e os cuidados necessários ao usar a criptografia
A criptografia, em termos simples, é uma forma de transformar os seus dados em um código secreto que só pode ser lido por quem tem a chave certa. Ela é essencial para garantir a segurança, a privacidade e a integridade dos dados confidenciais de sua aplicação.

A primeira e mais importante regra da criptografia é: **não tente inventar a sua criptografia**. Criar um algoritmo criptográfico seguro é uma tarefa muito difícil e complexa, que requer muito conhecimento e experiência. 

Por isso, você **deve usar os algoritmos criptográficos que já foram testados e aprovados por especialistas em criptografia**. Esses algoritmos são baseados em princípios matemáticos sólidos e foram submetidos a um rigoroso processo de análise e revisão. 

Não se esqueça que o .NET framework é o seu facilitador. Ele oferece várias implementações de algoritmos criptográficos padrão, que você pode usar em suas aplicações em C#. Você pode encontrar esses algoritmos na [biblioteca System.Security.Cryptography](https://learn.microsoft.com/pt-br/dotnet/standard/security/cryptography-model).

Vale destacar que é necessário utilizar os algoritmos mais fortes e modernos que estão disponíveis no .NET framework, pois eles oferecem uma maior proteção contra ataques e uma melhor eficiência na execução.

## Não confie nas entradas dos usuários
De maneira geral, as entradas dos usuários representam as informações recebidas do lado do client, e, em segurança, **a regra de ouro é não confiar cegamente no que os usuários possam inserir nas aplicações**. Por exemplo, imagine que você tem um método que recebe um número e calcula a sua raiz quadrada. Se você usar os dados do usuário como parâmetro para esse método, um agente mal intencionado pode enviar um valor negativo ou muito grande, e fazer o seu método dar um erro ou travar.

Para evitar esses problemas, **é crucial verificar e validar os dados de entrada do usuário**. Isso envolve pensar em todos os possíveis valores que esses dados podem ter e rejeitar aqueles que não são válidos ou esperados.

Além disso, é importante seguir algumas dicas de segurança fornecidas [nesta documentação oficial](https://learn.microsoft.com/en-us/dotnet/standard/security/security-and-user-input), tais como: 

- Evite usar funções como `Eval` ou inserir tags `<script>` nas aplicações web.

- Não confiar na URL solicitada pelo lado do client. Um atacante pode modificar a URL para acessar recursos não autorizados ou enviar dados falsos.

- Não aceitar caminhos de arquivos estranhos ou inválidos. Evite o uso de caracteres especiais (`*`), expansão de tokens (`%token%`), nomes alternativos de fluxo ou versões curtas de nomes de arquivos (`.filename::$DATA`).

## Fique por dentro das defesas contra ataques do tipo Injection
Injection está na terceira posição do [OWASP Top 10](https://owasp.org/Top10/A03_2021-Injection/), lista das dez categorias de ameaças mais comuns de segurança em aplicações web. O **Injection pode afetar vários tipos de interpretadores, como SQL, NoSQL, OS command, LDAP e outros**.

O SQL Injection, por exemplo, ocorre quando um atacante insere dados maliciosos em uma consulta SQL que é executada pelo seu banco de dados. Isso pode permitir que o atacante acesse, modifique ou apague dados sensíveis, ou execute comandos arbitrários no seu servidor.

Se você concatenar os dados fornecidos pelo usuário em uma consulta SQL sem validar ou escapar, você pode criar uma vulnerabilidade de SQL Injection.

Para evitar esse tipo de ataque, é essencial seguir as diretrizes de segurança recomendadas pela OWASP:

Utilize, sempre que possível, um [Mapeador Relacional de Objetos (Object-Relational Mapper; ORM)](https://learn.microsoft.com/en-us/ef/core/) ou procedimentos armazenados (_stored procedures_)  sempre que possível, pois são umas das formas mais eficazes de combater essas vulnerabilidades. Além disso, faça o uso também de consultas parametrizadas sempre que precisar empregar uma consulta SQL direta. 

Por exemplo, usando o **Entity Framework**:

```
var sql = @"Update [User] SET FirstName = @FirstName WHERE Id = @Id"; context.Database.ExecuteSqlCommand( sql, new SqlParameter("@FirstName", firstname), new SqlParameter("@Id", id));
```


**Evite a concatenação de strings em seu código para criar consultas que serão executadas em seu banco de dados**. Isso pode ser feito acidentalmente, mesmo com ORM ou procedimentos armazenados, portanto, verifique sempre. Por exemplo:


```
string sql = "SELECT * FROM Users WHERE UserName='" + txtUser.Text + "' AND Password='" + txtPassword.Text + "'"; context.Database.ExecuteSqlCommand(sql); // SQL Injection!

```

Para se prevenir aos demais tipos de Injection siga as demais recomendações informadas [nesta documentação da OWASP](https://cheatsheetseries.owasp.org/cheatsheets/DotNet_Security_Cheat_Sheet.html#updating-the-framework).

## Proteja os seus segredos com segurança
Segredos ou _secrets_ são informações confidenciais que você usa no seu código, como chaves de API, senhas de banco de dados, tokens de acesso e outros dados sensíveis. Esses segredos são essenciais para o funcionamento da sua aplicação, mas também são um alvo tentador para os atacantes. **Se os seus segredos forem expostos, você pode comprometer a segurança e a privacidade dos seus sistemas e dados**.

Uma das formas mais comuns de expor os segredos de codificação é codificá-los diretamente no seu código-fonte. Para evitar isso, você deve guardar os seus segredos em um lugar seguro, longe do seu código.

Uma prática segura comum é a de **utilizar variáveis de ambiente para armazenar segredos**. As variáveis de ambiente são armazenadas fora do nosso código e podem ser acessadas pela aplicação em tempo de execução. Para definir uma variável de ambiente, podemos usar o seguinte comando em um terminal ou prompt de comando:

```
set VARIABLE_NAME = "secret-value"
```

Para recuperar o valor de uma variável de ambiente em nosso código C#, podemos usar o seguinte trecho de código:

```
var secretValue = Environment.GetEnvironmentVariable("VARIABLE_NAME");
```


Mas atenção, você também deve evitar que os seus segredos sejam vazados por outros meios, como repositórios do Github e Gitlab ou em logs. Para isso, você pode usar ferramentas como o [Git Secrets](https://owasp.org/www-pdf-archive/OWASP_SCP_Quick_Reference_PT-BR_v1.0.pdf) ou o [Azure Key Vault](https://learn.microsoft.com/pt-br/aspnet/core/security/app-secrets?view=aspnetcore-7.0) para gerenciar os seus segredos.

## Desenvolvimento seguro em C# deve ser uma jornada contínua
Em um cenário de crescente ameaça cibernética, a segurança se tornou um dos maiores desafios para desenvolvedores atualmente. Não podemos mais negligenciar a proteção do nosso código e de nossas aplicações.

Para isso, **é fundamental adotar as melhores práticas de codificação segura, que têm o poder de prevenir ou minimizar os tipos mais comuns de ataques**. Essas práticas não devem ser consideradas como um obstáculo, mas como um alicerce sólido para construir aplicações robustas e confiáveis aos usuários.

No geral, a codificação segura em C# requer uma abordagem proativa e atenção aos detalhes. Ao seguir as práticas recomendadas discutidas neste artigo, você estará reduzindo de maneira significativa o risco de vulnerabilidades de segurança em seu código.

Para você seguir sua jornada de codificação segura C#, recomendo as seguintes referências técnicas de segurança de aplicações em C#:
- [Diretrizes de codificação segura para .NET - .NET | Microsoft Learn](https://learn.microsoft.com/pt-br/dotnet/standard/security/secure-coding-guidelines)
- [OWASP Cheat Sheet Series | OWASP](https://cheatsheetseries.owasp.org/cheatsheets/DotNet_Security_Cheat_Sheet.html)
- [OWASP Secure Coding Practices - Quick Reference Guide | OWASP](https://owasp.org/www-project-secure-coding-practices-quick-reference-guide/assets/docs/OWASP_SCP_Quick_Reference_Guide_v21.pdf)
- [Convenções de codificação C# da documentação do .NET - C# | Microsoft Learn](Convenções de codificação C# da documentação do .NET - C# | Microsoft Learn)