La codificación segura aborda vulnerabilidades como XSS y fugas de memoria de forma temprana, lo que aumenta la resiliencia del software y reduce los riesgos.
Las prácticas proactivas ahorran tiempo y dinero al evitar costosas correcciones posteriores al lanzamiento y fomentar la confianza del usuario.
Las mejores prácticas incluyen la validación de entradas, la protección del código de terceros y el aprovechamiento de herramientas como SAST para comprobaciones continuas.
Los estándares de OWASP, CERT y NIST ayudan a los desarrolladores a crear aplicaciones seguras y confiables.
Wiz Code admite la codificación segura con escaneos en tiempo real, comentarios procesables y orientación para proteger su SDLC.
¿Qué es la codificación segura?
La codificación segura es la práctica de desarrollar software que sea resistente a las vulnerabilidades de seguridad mediante la aplicación de las mejores prácticas, técnicas y herramientas de seguridad en las primeras etapas del desarrollo. En lugar de pensar solo en la experiencia del usuario, la codificación segura alinea cada función con las medidas de seguridad, desde el principio del ciclo de vida del desarrollo de software.
Por ejemplo, una aplicación que acepta todos los datos de un cliente sin desinfectarlos podría ser más fácil de implementar, usar y mantener. Sin embargo, abre un punto de entrada para que los atacantes inyecten código malicioso.
The Secure Coding Best Practices [Cheat Sheet]
With curated insights and easy-to-follow code snippets, this 11-page cheat sheet simplifies complex security concepts, empowering every developer to build secure, reliable applications.
Download Cheat SheetWhy is secure coding important?
La codificación segura incorpora la seguridad en el ADN de su software para evitar vulnerabilidades como la inyección de código SQL, los desbordamientos de búfer, las secuencias de comandos entre sitios y mucho más. Más allá de prevenir infracciones, es una forma de salvaguardar la confianza de los usuarios, desplazar la seguridad a la izquierda y cumplir con los estrictos estándares de las leyes de protección de datos.
¿La recompensa? Menos sorpresas desagradables después del lanzamiento, aplicaciones más sólidas y mejor protección tanto para los usuarios como para su organización.
Siete técnicas de codificación segura para crear software seguro
Un proceso de desarrollo de software seguro comienza con seguir las prácticas de codificación correctas que ayudan a prevenir vulnerabilidades y mantener sus aplicaciones seguras. Si usted'Si busca un recurso más detallado, asegúrese de consultar los requisitos de codificación segura de OWASP en su Guía para desarrolladores.
Mientras tanto, aquí hay algunas técnicas clave que puede comenzar a usar de inmediato para crear sistemas de software más seguros:
1. Utilizar lenguajes y herramientas modernas
Muchas vulnerabilidades de seguridad relacionadas con la memoria afectan a los lenguajes de programación con administración manual de memoria y sin comprobaciones de memoria integradas. Al iniciar un nuevo proyecto, asegúrese de que realmente necesita C/C++ para él y, si lo hace, use Punteros inteligentes y Analizadores de código estático para minimizar el impacto de los defectos lingüísticos.
Si necesita funciones de programación del sistema, un lenguaje más moderno como Óxido puede ser una buena opción porque su sistema de tipos comprueba el uso de memoria en tiempo de compilación. Zig También podría ser una buena alternativa, ya que no tiene flujo de control oculto ni asignaciones de memoria.
Si no necesita funciones de programación del sistema, el uso de un lenguaje de recolección de basura como Java o C# puede protegerlo de muchos problemas de memoria.
2. Valide y desinfecte los datos de entrada y salida
Los datos de usuario no validados son la razón principal de los fallos de inyección. Es por eso que es de vital importancia validar todos los datos que ingresan a su sistema. El saneamiento es otro paso que puede mantener la seguridad bajo control sin sacrificar la facilidad de uso. En lugar de rechazar una entrada de usuario si no es válida, el saneamiento eliminará las partes de entrada problemáticas (es decir, JavaScript dentro de HTML) y usará los datos restantes. Cuando se ejecute en un entorno cliente-servidor, asegúrese de que esta validación y saneamiento se realicen en el servidor. Esto significa sumar Validadores y desinfectantes a todos los puntos de conexión de la API que aceptan datos de usuario. También puede significar elegir formatos de datos que sean fáciles de validar, por ejemplo, aceptar Markdown simple en lugar de HTML completo.
Mantener limpios los datos de entrada no siempre es posible; Las bibliotecas de validación también tienen errores. Para asegurarse de que nada se filtre a sus usuarios, solo muestre las salidas basadas en las entradas del usuario de una manera segura (es decir, no represente HTML).
3. Comprobar la integridad del código de terceros
Las bibliotecas y los marcos de trabajo de terceros son salvavidas para acelerar el desarrollo, pero vienen con condiciones: no se construyeron en su casa. Trátalos como cualquier entrada a tu proceso de construcción: cuidadosamente examinados y bajo control.
¿Quieres evitar sorpresas desagradables? Anclar dependencias a Versiones específicas o hashes para evitar que las actualizaciones no probadas se cuelen en producción. Auditar y actualizar regularmente esas bibliotecas no es glamoroso, pero es la única forma de evitar que el código obsoleto se convierta en el talón de Aquiles.
4. Aplique un estricto control de acceso
El control de acceso limita quién puede ver o modificar el código y los recursos, protegiendo las funciones y los datos confidenciales de usuarios no autorizados. Cíñete a la Principio de privilegio mínimo: Proporcione a los usuarios solo lo que necesitan para hacer su trabajo, nada más y nada menos.
Para mejorar la seguridad, considere la posibilidad de implementar controles de acceso basados en roles (RBAC) y autenticación multifactor (MFA). Estas medidas reducen aún más la superficie de ataque y garantizan que personas no autorizadas no puedan acceder a sistemas o datos críticos.
5. Implemente el control y el registro de errores adecuados
Nadie quiere entregar a los atacantes una hoja de ruta, pero eso es exactamente lo que pueden hacer los mensajes de error demasiado detallados. Mantenga los detalles internos (por ejemplo, los seguimientos de pila y los errores de la base de datos) fuera del alcance de los usuarios. En su lugar, regístrese, de forma segura y reflexiva, solo para los ojos de su equipo.
Los buenos registros cuentan la historia: qué sucedió, cuándo y por qué. Monitorízalos en busca de algo sospechoso, pero no te excedas registrando datos confidenciales. El equilibrio es clave aquí: estás solucionando problemas, no exponiendo.
6. Automatiza las revisiones de código
Las revisiones manuales son importantes, pero la automatización es necesaria. Herramientas automatizadas como Pruebas estáticas de seguridad de aplicaciones (SAST) Y los linters señalan vulnerabilidades y errores de codificación más rápido de lo que los humanos podrían hacerlo.
Conecte estas herramientas a su canalización de CI/CD, y cada cambio de código se revisa antes de fusionarse. La retroalimentación inmediata mantiene a los desarrolladores informados y garantiza que las mejores prácticas de seguridad permanezcan en primer plano.
7. Aplicación de técnicas de ofuscación de código
La ofuscación de código no hace que tu aplicación sea a prueba de balas, pero ralentiza a los atacantes. El cambio de nombre de las variables a galimatías, la codificación de cadenas y la reestructuración del código dificultan la ingeniería inversa o el robo de propiedad intelectual.
Piense en ello como agregar camuflaje: la aplicación aún funciona sin problemas para los usuarios, pero a los malos actores les resultará mucho más difícil entrar o dar sentido a lo que ven. Cada obstáculo ayuda.
Vulnerabilidades comunes de software de código
Echemos un vistazo a las vulnerabilidades de seguridad comunes que los desarrolladores de software y los investigadores de seguridad han identificado. Pasaremos de problemas de bajo nivel, como vulnerabilidades de memoria, a problemas de nivel superior, como ataques de inyección.
Desbordamientos de búfer
Los desbordamientos de búfer pueden bloquear la aplicación o permitir que los atacantes escriban datos en otros búferes.
Los lenguajes de programación del sistema como C/C++ son propensos a esta vulnerabilidad. Permiten e incluso requieren la administración de memoria explícitamente, pero no comprueban el acceso a la memoria hasta que es demasiado tarde. Si escribe más datos en un búfer de los que le asignó en el momento de la definición, C invalidará todos los datos de memoria que siguen al final del búfer.
Ejemplo de un desbordamiento de búfer en C:
int b[5];
b[5] = 999; El búfer solo va de 0 a 4
Úselo después de gratis
El uso después de la liberación ocurre cuando se libera memoria en el montón pero se sigue usando el puntero anterior.
Una vez más, esta vulnerabilidad es prominente en lenguajes sin recolección de basura, como C/C++, donde debe administrar manualmente la memoria. Hay dos tipos de memoria: la pila y el montón. El lenguaje administra automáticamente la pila, que no puede contener datos con tamaños dinámicos que no se conocen en tiempo de compilación. El montón es para datos dinámicos, pero debe asignarlo manualmente y liberar espacio en él. Liberar significa que le dices al sistema operativo que ya no necesitas la memoria, por lo que si la usas después con un puntero, el acceso ilegal irá a una ubicación de memoria no asignada.
Ejemplo de uso después de la liberación en C:
char* p = (char*)malloc (16);
p = strdup("¡Un poco de texto!");
libre(p);
printf("%s", p); Imprime lo que ahora está en la memoria liberada
Doble gratis
En el caso de doble liberación, está liberando memoria de montón después de haberla liberado.
Double free es un problema en los lenguajes con administración manual de memoria, donde debe indicar explícitamente al sistema operativo que ya no necesita un rango de memoria específico. Si lo hace dos veces, se producirá un bloqueo similar al problema de uso después de la liberación. Esto suele ocurrir cuando hay varios objetos con punteros entre sí que se liberan en algún momento. Double free puede dañar la memoria a la que se hace referencia un puntero antes del primer free.
Ejemplo de doble libre en C:
char* p = (char*)malloc (16);
p = strdup("¡Un poco de texto!");
libre(p);
libre(p); corromperá lo que hay en la memoria liberada
Deserialización insegura
La deserialización insegura implica transformar directamente una estructura de datos externa (por ejemplo, JSON, XML, etc.) en una interna (por ejemplo, objetos, matrices, etc.) sin comprobaciones suficientes.
La deserialización insegura es una vulnerabilidad común en todo tipo de aplicaciones. Puede ser bueno aceptar datos no desinfectados durante el desarrollo, pero los usuarios pueden colar datos maliciosos sin previo aviso si se realiza en producción.
Ejemplo de deserialización insegura en JSON:
{
"nombre": "ejemplo",
"Correo electrónico": "email@example.com",
"isAdmin": true // debe eliminarse en el servidor
}
Fugas de memoria
Las pérdidas de memoria permiten que la aplicación consuma memoria sin límites. Si agota la memoria disponible y solicita más, la aplicación se bloqueará.
Todas las aplicaciones suficientemente complejas son susceptibles a esta vulnerabilidad. Incluso los idiomas recolectados como basura no están a salvo de las pérdidas de memoria. Los lenguajes de recolección de elementos no utilizados aún le permiten crear estructuras de datos que un recolector de elementos no utilizados no puede administrar.
Defectos de inyección
La ejecución de la entrada del usuario como código sin validarla se conoce como un defecto de inyección.
Este problema puede afectar a todas las aplicaciones, independientemente del lenguaje de programación utilizado. Una forma de hacer que su aplicación sea vulnerable a los errores de inyección es permitir que los usuarios agreguen código personalizado como una característica y no aislar la ejecución correctamente. Los desbordamientos de búfer que permiten a los atacantes escribir código en ubicaciones de memoria ejecutable son otra forma en que la aplicación puede volverse vulnerable a los errores de inyección.
Secuencias de comandos entre sitios (XSS)
El cross-site scripting es una versión web específica de un defecto de inyección. Aquí, un atacante inserta JavaScript personalizado oculto dentro del marcado HTML.
XSS puede ocurrir en todos los sitios web. Debido a que el marcado y el código ejecutable están estrechamente integrados en la web, es fácil introducir JavaScript en HTML, lo que filtra datos confidenciales.
Ejemplo de XSS en HTML y JavaScript:
<-- esto enviará una solicitud de recuperación
Cuando el ratón está sobre el botón <p> elemento-->
<p onmouseover="fetch('//example.com')">¡Hola mundo!</p>
Entidades externas XML (XXE)
Las entidades externas XML son otro ejemplo de un defecto de inyección. Todas las aplicaciones que usan XML son susceptibles a este ataque. La idea detrás de las entidades externas en XML es permitir la reutilización de archivos XML existentes. Sin embargo, un atacante puede usar esta función para incluir enlaces a archivos XML privados, lo que le permite leer datos privados indirectamente a través de su archivo XML cargado.
Ejemplo de inyección de entidades XML externas:
<?xml versión="1.0" codificación="ISO-8859-1"?>
<! DOCTYPE a [
<! ELEMENTO a CUALQUIERA >
<-- esto define una nueva entidad llamada xxe
desde un archivo privado -->
<! SISTEMA ENTITY xxe "file:///etc/passwd" >
]>
<-- aquí se representa la entidad para mostrar
el contenido del archivo -->
<a>&xxe;</a>
Referencia directa a objetos (IDOR) no segura
Cuando permite que las API públicas hagan referencia a objetos con identificadores secuenciales directamente, los identificadores pueden permitir que los atacantes adivinen el identificador de todos los objetos del servidor.
Este problema puede ocurrir en cualquier lugar donde se usen identificadores secuenciales para hacer referencia a objetos y es especialmente grave cuando se usan los identificadores para hacer referencia a objetos públicos y privados sin necesidad de autorización.
Ejemplos de URLs:
https://example.com/users/4539
https://example.com/users/4540
https://example.com/users/4541
Recorrido de directorios (también conocido como recorrido de ruta)
Otra falla de inyección es que los atacantes pueden atravesar rutas o estructuras de directorios a través de entradas de nombres de archivo.
Todas las aplicaciones que permiten la entrada de nombres de archivo pueden ser víctimas de esta vulnerabilidad. El recorrido de directorios puede ocurrir cuando los usuarios cargan varios archivos que hacen referencia entre sí a través de rutas relativas. Los atacantes pueden usar rutas de recorrido de archivos como ".." para navegar desde su directorio de carga en el servidor y en directorios con archivos de administradores u otros usuarios.
Ejemplo de recorrido de directorios en JavaScript en Node.js:
Esto carga un archivo javascript privado
const plantilla = require(".. /.. /.. /servidor/configuración/base de datos")
render(plantilla)
Estándares de seguridad del código
Los estándares de codificación segura son conjuntos de directrices y mejores prácticas que siguen los desarrolladores para crear software seguro y minimizar las vulnerabilidades. Abordan errores y debilidades comunes de codificación que pueden ser explotados por los atacantes, con el objetivo de crear un código más resistente y resistente.
A continuación se muestran los estándares comunes de código seguro a seguir:
1. Prácticas de codificación segura de OWASP:
Las Prácticas de Codificación Segura (SCP) de OWASP son directrices del Proyecto de Seguridad de Aplicaciones Web Abiertas que se centran en áreas clave para mejorar la seguridad del software, como la validación de entradas, la autenticación, la gestión de sesiones, el cifrado y la gestión de errores. Es una hoja de ruta para un código más seguro, desde su Primera confirmación para la implementación final.
2. Estándares de codificación segura de CERT:
Los Estándares de Codificación Segura (SCS) del CERT son un conjunto de directrices y recomendaciones desarrolladas por el Instituto de Ingeniería de Software (SEI) de la Universidad Carnegie Mellon para ayudar a los desarrolladores a escribir código seguro y prevenir vulnerabilidades. Principales áreas de interés:
Directrices específicas para cada idioma:Ofrece recomendaciones para C, C++, Java, Android y Perl para abordar vulnerabilidades comunes en esos lenguajes.
Programación defensiva:Enfatizar la anticipación y el manejo de los errores con elegancia para evitar la explotación.
Gestión de la memoria:Concéntrese en evitar desbordamientos de búfer y pérdidas de memoria, especialmente en lenguajes como C y C++.
3. Directrices de codificación segura del NIST:
Las directrices de codificación segura del NIST (también conocidas como Publicación especial del NIST 800-218) se centran en áreas críticas como la validación de entradas, la autenticación, el cifrado y la gestión de errores, y ofrecen consejos claros para mantener los ataques de inyección, el secuestro de sesiones y los problemas de memoria fuera de su software. Si desea un sello de aprobación respaldado por el gobierno en su Prácticas de seguridad del código, esta es tu opción.
ISO/IEC 27001 es una norma internacional de seguridad de la información. Si bien'No es específicamente un estándar de codificación segura, pero sí incluye requisitos para prácticas de codificación segura como parte de un enfoque integral de gestión de la seguridad. El Anexo A, Control 8.28: Prácticas de codificación segura, se centra específicamente en la codificación segura y hace hincapié en cómo las organizaciones deben:
Desarrolle procesos de codificación seguros para el desarrollo interno y el código de terceros.
Manténgase informado sobre la evolución de las amenazas y vulnerabilidades.
Implemente principios sólidos de codificación segura para abordarlos.
Garantiza un ciclo de vida de desarrollo de software seguro con Wiz
La codificación segura es una práctica que afecta a todos los aspectos del desarrollo de software, desde la elección de los formatos de datos y los lenguajes de programación hasta la planificación de las entradas y salidas y la implementación.
Nosotros're emocionado de presentar Código Wiz, nuestra última innovación diseñada para capacitar a los desarrolladores y equipos de seguridad para implementar y mantener prácticas sólidas de codificación segura a lo largo de todo el ciclo de vida del desarrollo de software.
Wiz Code amplía nuestra plataforma de seguridad en la nube para cubrir todas las etapas del desarrollo, ofreciendo potentes capacidades para respaldar sus iniciativas de codificación segura:
Escaneo de código integrado: Detecte vulnerabilidades, errores de configuración y problemas de cumplimiento directamente en su IDE y repositorios de código, detectando posibles problemas antes de que lleguen a producción.
Comentarios de seguridad en tiempo real: Obtenga información de seguridad instantánea a medida que codifica, lo que permite a los desarrolladores abordar los problemas de inmediato y aprender prácticas de codificación seguras sobre la marcha.
Trazabilidad de la nube al código: Rastree los riesgos descubiertos en los entornos de producción hasta el código específico y los equipos que los introdujeron, lo que facilita un análisis y una corrección rápidos de la causa raíz.
Guía de corrección en el código: Reciba recomendaciones prácticas y contextuales para solucionar problemas de seguridad directamente en su entorno de desarrollo.
Soporte lingüístico integral: Benefíciese de las mejores prácticas de codificación segura en una amplia gama de lenguajes de programación y marcos.
Secure your SDLC from start to finish
See why Wiz is one of the few cloud security platforms that security and devops teams both love to use.