Os ficheiros de bloqueio desempenham um papel vital na segurança da cadeia de fornecimento de software através de uma gestão consistente das dependências. Especificam as versões exactas das dependências utilizadas, assegurando a reprodutibilidade e evitando alterações inesperadas.
Num ambiente de desenvolvimento acelerado, repleto de bibliotecas de código aberto e pacotes de terceiros, os ficheiros de bloqueio funcionam como uma defesa contra ataques à cadeia de fornecimento. Ao bloquear dependências para versões específicas, impedem actualizações automáticas para versões potencialmente comprometidas.
Muitas equipas de desenvolvimento ignoram os ficheiros de bloqueio, não conseguindo utilizar todo o seu potencial. Este artigo destaca a importância dos ficheiros de bloqueio para garantir a integridade e a segurança do projeto de software.
Compreender os ficheiros de bloqueio
Os arquivos de bloqueio são arquivos que capturam as versões exatas de cada dependência e suas subdependências em um projeto. Garantem a uniformidade das versões das dependências em todas as instâncias de um projeto, evitando o "inferno das dependências" e potenciais riscos de segurança.
Os ficheiros de bloqueio são diferentes para cada língua e podem diferir consoante as estruturas, mas geralmente seguem formatos semelhantes.
Javascript - yarn.lock
lodash@^4.17.15:
versão "4.17.21"
resolvido "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#acfcd7438b5d260f06a1d052c2a3b32ddc91c6b8"
integridade sha512-v2kDE6syb5rK+X8bykjh3W7n4P3NV8axFypa8DwO8DK+RVZk9vft6xEhjxzIlc6DCwCPkMKSk4eQF6QNHOu9pw==
react@^17.0.1:
versão "17.0.2"
resolvido "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#cdc8d94b0d7091f440c51d1427ff2a3d6e14e664"
integridade sha512-y8vQ43+qMOpbD/3k1Vw4E4i4UgFqxMwI0AZc5fxyIfZK4kHRZ5Klg5zh/5Nq1Nk3JZqf6byFAkyoGZkbSnYt9w==
Python - poetry.lock
[[package]]
name = "requests"
version = "2.25.1"
description = "Python HTTP for Humans."
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
[package.dependencies]
certifi = ">=2017.4.17"
chardet = ">=3.0.2,<5"
idna = ">=2.5,<3"
urllib3 = ">=1.21.1,<1.27"
Esta entrada especifica o nome do pacote (clique), os hashes aceites e a versão exacta (8.0.3). Essa especificidade garante instalações consistentes em ambientes de desenvolvimento, teste e produção.
Os gestores de pacotes geram ficheiros de bloqueio durante a instalação de dependências ou actualizações. É essencial submeter estes ficheiros ao controlo de versões com o código-fonte do projeto. Esta prática garante que todos os colaboradores do projeto utilizam dependências idênticas, reduzindo as inconsistências e tornando as compilações mais previsíveis.
Diferentes linguagens e gerenciadores de pacotes têm seus próprios formatos de arquivo de bloqueio: O Node.js usa o package-lock.json para o npm, o Python usa o Pipfile.lock para o Pipenv e o Ruby usa o Gemfile.lock para o Bundler. O uso de lockfiles ajuda a manter uma base de projeto consistente e segura, reduzindo os riscos associados ao gerenciamento de dependências.
Defesa contra ataques à cadeia de abastecimento
Os ataques à cadeia de abastecimento em dependências de código aberto são cada vez mais comuns. Os atacantes podem comprometer uma biblioteca popular, injectando código malicioso que se espalha para projectos dependentes. Os arquivos de bloqueio fornecem uma forte defesa contra esses ataques.
Ao especificar as versões exactas das dependências, os ficheiros de bloqueio evitam actualizações automáticas para versões potencialmente comprometidas. Isto é crucial quando são identificadas vulnerabilidades nas dependências. Com os ficheiros de bloqueio, os projectos permanecem estáveis com versões seguras conhecidas até que a equipa decida atualizar após testes exaustivos.
Abaixo está um exemplo de um package-lock.json
usado em projetos Node.js para bloquear versões específicas de dependências. Isso garante que todos que trabalham no projeto instalem exatamente as mesmas versões, promovendo consistência e segurança.
{
"name": "my-project",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "my-project",
"version": "1.0.0",
"dependencies": {
"lodash": "4.17.21",
"axios": "0.21.1"
}
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDE6syb5rK+X8bykjh3W7n4P3NV8axFypa8DwO8DK+RVZk9vft6xEhjxzIlc6DCwCPkMKSk4eQF6QNHOu9pw=="
},
"node_modules/axios": {
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
"integrity": "sha512-pbkHfFgC6F4ltGeoyTeHRtUkZo/FZ9EoElV3MzDLeO2uYxLqGm6Qcbx93jUOJISyYSC/tzjK4NHH3MAYsDKUTA==",
"dependencies": {
"follow-redirects": "^1.10.0"
}
},
"node_modules/follow-redirects": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz",
"integrity": "sha512-0gh4nEbdUdDra9mJKpAB+Y4gG61sQiKsbiqS8c5LEnFOh8fbov3/xp0FnWE2+IxKTozhJSdEV8ujvQjU+Ub3dg=="
}
},
"dependencies": {
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDE6syb5rK+X8bykjh3W7n4P3NV8axFypa8DwO8DK+RVZk9vft6xEhjxzIlc6DCwCPkMKSk4eQF6QNHOu9pw=="
},
"axios": {
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
"integrity": "sha512-pbkHfFgC6F4ltGeoyTeHRtUkZo/FZ9EoElV3MzDLeO2uYxLqGm6Qcbx93jUOJISyYSC/tzjK4NHH3MAYsDKUTA==",
"requires": {
"follow-redirects": "^1.10.0"
}
},
"follow-redirects": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz",
"integrity": "sha512-0gh4nEbdUdDra9mJKpAB+Y4gG61sQiKsbiqS8c5LEnFOh8fbov3/xp0FnWE2+IxKTozhJSdEV8ujvQjU+Ub3dg=="
}
}
}
O que faz este ficheiro
- Bloqueia versões específicas:
Bloqueiachicote
na versão 4.17.21 eáxis
em 0.21.1. Independentemente de quando ou onde instalar este projeto, serão utilizadas estas versões exactas - evitando actualizações acidentais para versões que possam conter alterações de rutura ou problemas de segurança. - Captura a árvore de dependências:
Inclui dependências aninhadas, comoseguir-redirecções
, que é utilizado internamente poráxis
. - Suporta ferramentas de segurança:
Ferramentas como Aikido utilizam este ficheiro de bloqueio para procurar vulnerabilidades conhecidas. Uma vez que o ficheiro contém URLs resolvidos e hashes de versão, os scanners podem:- Identificar com exatidão os pacotes de risco.
- Recomendar alternativas corrigidas ou seguras.
- Acompanhar as alterações às dependências ao longo do tempo.
Riscos de ignorar os ficheiros de bloqueio
Negligenciar os ficheiros de bloqueio pode desestabilizar e comprometer os projectos de software. Sem lockfiles, as versões de dependência podem variar entre ambientes, levando a inconsistências que complicam a depuração. Estas variações podem causar bugs evasivos, atrasando projectos e aumentando os encargos de manutenção.
Sem um ficheiro de bloqueio, o acompanhamento das dependências torna-se um desafio. A ausência de um registo claro torna difícil determinar que versões são utilizadas, complicando a gestão da cadeia de fornecimento. No caso de uma vulnerabilidade, os programadores têm dificuldade em identificar rapidamente as dependências de risco, atrasando os tempos de resposta.
As actualizações automáticas representam riscos significativos quando os ficheiros de bloqueio estão ausentes. As actualizações não controladas podem introduzir pacotes comprometidos, expondo os projectos a falhas de segurança. Até mesmo bibliotecas respeitáveis podem abrigar ameaças ocultas, tornando a supervisão dos arquivos de bloqueio crucial para manter uma base de código segura.
Melhores práticas para a utilização de ficheiros de bloqueio
Integre os ficheiros de bloqueio no seu fluxo de trabalho de desenvolvimento para tirar o máximo partido dos mesmos. A inclusão de ficheiros de bloqueio no controlo de versões estabelece uma única fonte de verdade para as dependências, promovendo um ambiente de desenvolvimento consistente. Esta abordagem reduz as variações indesejadas e aumenta a fiabilidade da produção.
A atualização e revisão regular dos ficheiros de bloqueio é vital para a deteção precoce de ameaças. Esta estratégia proactiva ajuda as equipas a resolver rapidamente as vulnerabilidades, mantendo uma forte postura de segurança. Utilize ferramentas para avaliação contínua de dependências para automatizar a deteção de riscos na cadeia de fornecimento de software.
A ancoragem de dependências a versões específicas em ficheiros de manifesto aumenta a segurança. Essa prática complementa os arquivos de bloqueio e serve como uma rede de segurança em caso de discrepâncias. Educar as equipas de desenvolvimento sobre a importância dos ficheiros de bloqueio reforça a gestão diligente das dependências, aumentando a segurança geral.
Mantendo as Dependências Atualizadas com Lockfiles
Manter as dependências actualizadas requer a combinação da automatização com uma revisão minuciosa. As actualizações de rotina dos ficheiros de bloqueio devem fazer parte dos ciclos de desenvolvimento, incorporando as últimas melhorias e correcções de segurança, preservando a consistência. As actualizações regulares minimizam as interrupções inesperadas e reforçam a segurança.
Ferramentas automatizadas como o Dependabot ajudam a gerir as actualizações, gerando pedidos pull para novas versões de dependências. Estas ferramentas fornecem monitorização contínua, permitindo actualizações atempadas e permitindo que as equipas se concentrem noutras tarefas. No entanto, é crucial rever as alterações para garantir que satisfazem as necessidades do projeto e evitar problemas.
O desenvolvimento de um processo de atualização manual de ficheiros de bloqueio é também essencial. Implementar dependências actualizadas num ambiente de teste para avaliar o impacto e a compatibilidade. Esta abordagem evita interrupções e mantém a coerência, minimizando os riscos de mudanças frequentes de versão.
A incorporação de ficheiros de bloqueio no seu processo de desenvolvimento reforça a sua cadeia de fornecimento de software contra ameaças de segurança em evolução. A adoção de melhores práticas e a promoção da consciência de dependência na sua equipa são fundamentais para manter uma base de código robusta. Pronto para melhorar a segurança da sua cadeia de fornecimento? Comece gratuitamente com o Aikido e simplifique o seu percurso de segurança.