Evitando la inyección de la cáscara al llamar a Git en Python -- python campo con strings campo con security campo con child-process campo con git camp codereview Relacionados El problema

Avoiding shell injection when calling Git in Python


8
vote

problema

Español

Estoy desarrollando una aplicación de línea de comandos en Python que procesa la información que proporcionan los usuarios. He estado leyendo la documentación de Python en este tema y encontrado que el módulo incorporado subprocess proporciona el método 9988776665544331 , que ejecuta una cadena como si se ejecutara en una línea de comandos. La desventaja de este enfoque es que puede llevar a inyección de cáscara .

La solución que acumulé con usos un conjunto de subcadenas ilegales, como rm o -rf3 y luego usa la regex para verificar si la cadena provista contiene una subcadena de el conjunto.

  import re from string import ascii_letters, punctuation  # Generate a set of characters used for string sanitization. punctuation_minus = set(punctuation) - set(('.', '_', '-')) substrings = set(("rm", "&&", "-f", "null", "/dev/null", "2>&1", "-rf",               "rf")) illegal = [re.escape(item) for item in (punctuation_minus | substrings)] illegal_as_str = "|".join(illegal)  def sanitize_string(s):     """Cleans a string from illegal characters."""     # Get all legal strings.     operations = re.split(illegal_as_str, s)     # Remove trailing spaces     no_trailings = [x.strip() for x in operations]     # Remove empty strings.     list_of_operations = filter(None, no_trailings)     # Generate a safe string to return.     operations_str = " ".join(list_of_operations)     try:         operations_str.decode("utf-8")         return operations_str     except UnicodeDecodeError as detail:         print("UnicodeDecodeError: " + str(detail))         return False   

El problema inherente con este enfoque es que depende en gran medida del conjunto de caracteres ilegales que estoy usando. ¿Hay alguna forma en que pueda desinfectar una cadena teniendo en cuenta los ataques comunes? Y si no, ¿cómo puedo mejorar mi código?

Se espera que el usuario proporcione comandos GIT, como git add o git push . Cada uno de estos comandos GIT necesita ciertos parámetros que el usuario debe proporcionar. El siguiente ejemplo muestra cómo se eliminan todas las subcadenas ilegales de una entrada de usuario al agregar archivos al área de estadificación:

  >>> git_add_str = "git add {}" >>> files_to_add = input("Files to add as string:") Files to add as string: "file1.py file2.py; rm -rf /" # Clean files_to_add before modifying git_add_str. >>> clean_str = sanitize_string(files_to_add) >>> clean_str 'file1.py file2.py' >>> git_add_str = git_add_str.format(clean_str) >>> git_add_str 'git add file1.py file2.py'   

Esta salida se considera legal, ya que no contiene ninguna de las subcadenas ilegales. Ahora es seguro ejecutar subprocess.call con esta cadena y shell=True9 .

Original en ingles

I'm developing a command line application in Python which processes information that users provide. I've been reading the Python documentation on this topic and found that the built-in module subprocess provides the call method, which executes a string as if it was run on a command line. The disadvantage of this approach is that it can lead to shell injection.

The solution I came up with uses a set of illegal substrings, such as rm or -rf, and then uses regex to check whether the provided string contains a substring from the set.

import re from string import ascii_letters, punctuation  # Generate a set of characters used for string sanitization. punctuation_minus = set(punctuation) - set(('.', '_', '-')) substrings = set(("rm", "&&", "-f", "null", "/dev/null", "2>&1", "-rf",               "rf")) illegal = [re.escape(item) for item in (punctuation_minus | substrings)] illegal_as_str = "|".join(illegal)  def sanitize_string(s):     """Cleans a string from illegal characters."""     # Get all legal strings.     operations = re.split(illegal_as_str, s)     # Remove trailing spaces     no_trailings = [x.strip() for x in operations]     # Remove empty strings.     list_of_operations = filter(None, no_trailings)     # Generate a safe string to return.     operations_str = " ".join(list_of_operations)     try:         operations_str.decode("utf-8")         return operations_str     except UnicodeDecodeError as detail:         print("UnicodeDecodeError: " + str(detail))         return False 

The inherent issue with this approach is that it heavily depends on the set of illegal characters I'm using. Is there any way I can sanitize a string taking into account the common attacks? And if not, how can I improve my code?

The user is expected to provide git commands, such as git add or git push. Each one of these git commands needs certain parameters that the user needs to provide. The next example shows how all the illegal substrings are removed from a user input when adding files to the staging area:

>>> git_add_str = "git add {}" >>> files_to_add = input("Files to add as string:") Files to add as string: "file1.py file2.py; rm -rf /" # Clean files_to_add before modifying git_add_str. >>> clean_str = sanitize_string(files_to_add) >>> clean_str 'file1.py file2.py' >>> git_add_str = git_add_str.format(clean_str) >>> git_add_str 'git add file1.py file2.py' 

This output is considered legal as it does not contain any of the illegal substrings. Now it is safe to run subprocess.call with this string and shell=True.

              
         
         

Lista de respuestas

11
 
vote
vote
La mejor respuesta
 

Su estrategia de defensa se conoce como "enumerando la maldad" . Como regla general, cualquier estrategia basada en la maldad enumeración está condenada a fallar. Por ejemplo, prohíbe rm -rf / , pero ¿ha considerado find / -delete , que básicamente hace lo mismo? ¿Qué tal algún uso del dd if=/dev/zero ? ¿Qué sucede si un usuario quiere legítimamente realizar una operación en un archivo llamado normal.py o incluso 9988777665544334 ? ¿Por qué estás alterando silenciosamente el comando para hacer algo más ?

Si alguna vez lo necesitaba para ejecutar un programa externo con parámetros suministrados por el usuario, las prácticas razonables serían usar subprocess.run() o subprocess.Popen()

  • con la línea de comandos como una lista ya dividida en palabras,
  • Con el parámetro shell=False (la mejor manera de evitar la inyección de cáscara es evitar usar el shell en absoluto!),
  • Con el comando dado usando una ruta absoluta (que es esencial con shell=False ),
  • Con -- que precede a los nombres de archivos suministrados por el usuario, para que los nombres de archivo que comiencen con find / -delete0 se tratan literalmente.

no intente prohibir las palabras "malas"; Desea que su código funcione para cualquier nombre de archivo legítimo legítimo. do Compruebe que los nombres de archivo son legítimos, aunque ", por ejemplo, que no contengan demasiados find / -delete1 .

Mejor aún, use una Módulo de Python que se encarga de interactuar con git para que no tenga Para lidiar con el problema usted mismo.

 

Your defense strategy is known as "enumerating badness". As a rule, any strategy based on enumerating badness is doomed to fail. For example, you prohibit rm -rf /, but have you considered find / -delete, which basically does the same thing? How about some use of the dd if=/dev/zero? What if a user legitimately wants to perform an operation on a file named normal.py or even rm.c? Why are you silently altering the command to do something else?

If you ever need to execute an external program with user-supplied parameters, sensible practices would be to use subprocess.run() or subprocess.Popen()

  • with the command line as a list already split into words,
  • with the shell=False parameter (the best way to avoid shell injection is to avoid using the shell at all!),
  • with the command given using an absolute path (which is essential with shell=False),
  • with -- preceding the user-supplied filenames, so that filenames that start with - are treated literally.

Do not attempt to prohibit any "bad" words; you want your code to work for any legitimate filenames. Do check that the filenames are legitimate, though xe2x80x94 for example, not containing too many ../../../...

Better yet, use a Python module that takes care of interacting with Git so that you don't have to deal with the problem yourself.

 
 
 
 

Relacionados problema

5  Herramienta para calcular el tiempo promedio que toma para una solicitud de tracción GitHub para fusionar  ( Tool to calculate the average time that takes for a github pull request to get m ) 
Estoy aprendiendo, y este es mi primer intento de una herramienta de línea de comandos que usa la API de GitHub para calcular el tiempo promedio que toma una ...

3  Restablecer archivos en GIT que se muestran como modificados pero no tienen cambios de acuerdo con "Git Diff"  ( Reset files in git which show as modified but have no changes according to git ) 
Este parece para estar funcionando, pero también es bastante lento y me parece un poco hackeado. IFS=$' ' for currentFile in $(git status | grep "modifi...

5  Base para la iteración sobre la historia del git  ( Base for iterating over git history ) 
Quería hacer algunas estadísticas sobre la historia de un repositorio de git. Al principio, intenté usar Gitpython, pero no era tan trivial como lo imaginaba....

4  Descarga un git repo sin .git carpeta  ( Download a git repo without git folder ) 
Viniendo de Python, JavaScript y PHP, me gustaría aprender a escribir Ruby en la forma en que se "supone". El código de Python bien escrito se llama "Pythonic...

8  Bash Script para clonar todos los repositores públicos o gistas para un usuario específico, opcionalmente a un directorio de elección  ( Bash script to clone all public repos or gists for a specified user optionally ) 
Escribí este script como una forma de hacer una copia de seguridad y / o descargar rápidamente un conjunto de repos o gistas de un usuario. No tengo ninguna p...

2  Programa de Kotlin para resumir Git Comets by Rogex Match  ( Kotlin program to summarize git commits by regex match ) 
Estoy tratando de aprender Kotlin. Vengo de algunos antecedentes en Java. Como ejercicio de aprendizaje, escribí este programa simple para resumir las ocurren...

10  Script de bash para simplificar el flujo de trabajo de implementación del GIT  ( Bash script to simplify git deployment workflow ) 
En mi empresa, sigo el siguiente flujo de trabajo. (Creo que se puede definir un tipo de 'integración continua'.) flujo de trabajo: Tenemos 3 sucursale...

4  Script de rubí para crear repos de git  ( Ruby script to create git repos ) 
Escribí mi primer script de rubí, por este tutorial . Crea un repo de git local y remoto. He estado trabajando durante aproximadamente 3 años con PHP, y de...

10  Nivel faltante de profundidad técnica (ancestro común)  ( Missing level of technical depth common ancestor ) 
Recientemente le hemos dado una prueba de codificación en una compañía de TI de buena reputación. Hubo tres preguntas de codificación. me rechazaron diciend...

1  Git AutoUpandater  ( Git autoupdater ) 
En mi oficina, tenemos una herramienta de monitoreo interno que utilizamos en los sistemas de clientes para monitorear varios vitales y notificarnos a través ...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos