0

I decided to store my python app configurations in yml file. My yml file looks something like this:

config.yml

name: firstApp
base_dir: "Path(__file__).resolve(strict=True).parent.parent"
secret_key: "a passphrase for peppering"
mysql: 
    host: localhost
    user: root
    passwd: "my secret password"

I then import the yml file using pyyaml library:

config.py

import yaml
config = yaml.safe_load(open('path/to/config.yml'))

currently config.base_dir returns Path(__file__).resolve(strict=True).parent.parent but I want it to return the output of the python code which relies on running from pathlib import Path first.

using eval and exec is frowned upon. But I do not see any other way around it. Looking for some guidance and a way to do this without any security concerns.

Thanks,

Community
  • 1
  • 1
syrkull
  • 2,295
  • 4
  • 35
  • 68
  • There is no other way except those — so you have to live with the security risks if you decide you must be able to do it. – martineau May 31 '20 at 07:29

1 Answers1

0

By definition, running code from within a text file which is writable by external entities, is a potential security hazard. The traditional way to try and support such things is to run the code in a "sandbox" (a restricted environment with limited permissions), however that's not exactly trivial (see some basic details here and a more complete answer in Software Engineering Stack Exchange) - unless you can define very accurate permissions of what the code should and should not be able to do, this is going to be a configuration headache, which is going to be very OS specific.

When I need similar configs to what you presented, usually I define tokens such as {current_file_path} and other magic values and interpret them when they appear in strings - in your case it would be {current_file_path}/../.. which would obtain the same result as the proposed code (assuming you do resolve the path).

If you can define a list of the capabilities you do wish to support, it would possibly enable providing a more secure solution for your usecase.

Barak Itkin
  • 4,872
  • 1
  • 22
  • 29
  • can you show how you define 'tokens'? and how you replace them after you imported the config,yml? – syrkull May 31 '20 at 09:31
  • There's nothing intelligent about how I replace text - I just add a dictionary of values and then replace with `for k, v in PREDEFINED: value = value.replace(k, v)`. Note that if you want some fields to automatically construct a configuration object or run through some evaluation, you could use custom tags - take a look at https://stackoverflow.com/a/43060743/748102 for syntax such as `base_dir: !ResolvePath "{curr_dir}/../.."`(this way you won't have to explicitly remember processing each such field). – Barak Itkin May 31 '20 at 10:17