"não existem linguagens mais seguras do que outras"
Estritamente isso está certo. Tem reflexões que precisam ser feitas, precisa cavar mais a fundo algumas questões, mas o que importa na linguagem de programação, apesar de poder ter alguma fora da curva, no mal sentido, e ter sim algum problema de segurança, as mainstream e muitas que não são, todas tem o mesmo nível de segurança geral.
Existem algumas que exigem mais cuidado do programador que outras. Existem algumas que a biblioteca parão pode ter partes inseguras, mas a linguagem não é insegura. Ultimamente o mercado, como sempre, andou tentando vender essa ideia, mas não tem base nos fundamentos da computação, com todas as ressalvas feitas. Hoje a maioria acha que Rust é segura e C++ não é. Ou que Java é mais segura que C# porque esta tem um comando chamado unsafe
, ou sobre vários outros mitos que a maioria fala.
Um outro detalhe é que a implementaçao de uma linguagem ter uma falha de segurança não é o memso que a linguagem ter.
E segurança nesse contexto não é o mesmo de segurança de tipo, de concorrência ou de gerenciamento de memória. Pelo menos não diretamente, está se falando da possibilidade de ataque externo ao código, não do erro do programador.
Conceitos como memory-safety e type-safety existem desde pelo menos os anos 60, então o senso comum de que o assunto é algum tipo de "novidade" ou "moda" está errado. O senso comum de que isso é orientado por "mercado" também está errado, pois é puramente acadêmico. O senso comum de que "a linguagem não tem problemas de segurança, a culpa é do programador" também está errado. O senso comum de que segurança é uma dicotomia também está errado. E o último senso comum também está errado: segurança não é só sobre vulnerabilidades e código (implementação).
Quando digo que uma linguagem tem um problema (repare no termo usado) de segurança não estou dizendo que o código da implementação tem algo errado nem dizendo que a linguagem tem uma vulnerabilidade. Segurança é muito mais complexo do que isso, vulnerabilidade em código é só a ponta do iceberg.
Antes de explicar vale deixar uma nota: safe e secure não é a mesma coisa, os dois são traduzidos para "seguro" em português e acaba perdendo essa distinção. Mas safe é mais no sentido de confiável (como sua casa que é safe) e secure é mais no sentido de protegido (como um banco que é secure).
Unsafe
Deixa eu explicar o que é um código unsafe: é basicamente código onde resultados inesperados e fora do controle do programador podem acontecer. Um exemplo em C:
char *ex = malloc(32);
strcpy(ex, "hello");
Esse código é unsafe porque ex
pode ser NULL e quando strcpy()
recebe NULL o comportamento é indefinido (undefined behavior - UB). Ou seja, se o código pode causar UB então ele é chamado de unsafe ("não-confiável" traduzido de maneira não literal).
Linguagens que não tem UB no seu dialeto padrão são safe ("confiáveis") e a palavra-chave unsafe é usada justamente para indicar trechos de código que podem causar UB (código "não-confiável").
Ok, e o que UB tem a ver com segurança? Bem, eu explico: a gigantesca maioria das vulnerabilidades em binários são causadas por UB. Para servir de evidência do que estou falando vejamos as últimas CVE reportadas para o kernel Linux:
- CVE-2023-50431: sec_attest_info in drivers/accel/habanalabs/common/habanalabs_ioctl.c in the Linux kernel through 6.6.5 allows an information leak to user space because info->pad0 is not initialized.
- Isso é um UB
- CVE-2023-47233: The brcm80211 component in the Linux kernel through 6.5.10 has a brcmf_cfg80211_detach use-after-free in the device unplugging (disconnect the USB by hotplug) code.
- Isso é um UB
- CVE-2023-46862: An issue was discovered in the Linux kernel through 6.5.9. During a race with SQ thread exit, an io_uring/fdinfo.c io_uring_show_fdinfo NULL pointer dereference can occur.
- Isso é um UB
- CVE-2023-46813: An issue was discovered in the Linux kernel before 6.5.9, exploitable by local users with userspace access to MMIO registers. Incorrect access checking in the #VC handler and instruction emulation of the SEV-ES emulation of MMIO accesses could lead to arbitrary write access to kernel memory (and thus privilege escalation). This depends on a race condition through which userspace can replace an instruction before the #VC handler reads it.
- Isso é um UB
- CVE-2023-45898: The Linux kernel before 6.5.4 has an es1 use-after-free in fs/ext4/extents_status.c, related to ext4_es_insert_extent.
- Isso é um UB
Ou seja, dentre as 5 últimas CVE do Linux todas elas são UB... Coincidência? Não.
Ok, agora você deve tá pensando: "ah, mas UB não é uma vulnerabilidade de segurança."
E ninguém disse que era, é um risco de segurança. Um risco e não uma vulnerabilidade. E riscos de segurança são problemas de segurança.
Pensa assim: você deixar seu carro aberto no meio da rua e com a chave na ignição não é um mal funcionamento na tranca do veículo nem na ignição. Mas mesmo assim você será roubado, porque você se sujeitou ao risco disso acontecer em um ambiente favorável a "dar merda".
O mesmo vale para riscos de segurança em linguagens de programação. Sim, podemos dizer que "a culpa é do programador" de certo modo: a culpa é dele por não ter conhecimento para entender o risco ao qual ele estava se sujeitando e fazer "pouco caso" do assunto.
E caso não tenha ficado claro, riscos de segurança são problemas de segurança. É um problema a ser resolvido, não é algo que deve ser aceito como "normal" ou como as coisas deveriam ser. Se o risco poderia ser evitado então isso é uma falha de design na linguagem de programação (pois é, problemas de segurança não existem apenas em código...).
Ok, riscos sempre existirão e não é tecnicamente possível mitigar todos. Mas existem vários riscos que podem ser mitigados, como os UB por exemplo.
Escolher por manter riscos que podem ser mitigados em linguagens de programação é como escolher deixar o carro aberto com a chave na ignição: é burrice, é óbvio que vai dar merda. Sempre deu e sempre dará.
Então não importa o quanto o programador tenha a crença de que é "foda", se o risco existe vai dar merda (lei de Murphy sempre funciona quando o assunto é segurança). A evidência disso é que todo projeto em C conhecido têm, todo ano, dezenas ou até centenas de CVE que foram causadas por causa de UB na linguagem.
Então o simples fato da linguagem não ter UB no seu dialeto padrão faz com que sim, a linguagem seja mais segura do que C (que tem muito UB).
Menos risco é sinônimo de mais segurança, e isso vale para segurança física também. Por exemplo: você está mais seguro em casa ou em uma corda bamba pendurada em um penhasco? O que é mais seguro: escalar um poste de alta tensão bêbado ou sóbrio e com todo o EPI necessário?
Repito: menos risco é mais segurança.