Protecting an API key in Python - python

I am writing a Python program which uses an API Key to access data from an external service. The program makes a call to this service with the key hard coded in my Python script. Is there a method of somewhat protecting this key (not something that is irreversible, but a method preventing people copying the key straight out of the script)? Should the program request the key from my server? Perhaps a C library?

If you want to protect yourself from "Hackers", it is impossible, since if python script has access to your API, then this same script can be modified to do nasty things with the access it possesses. You will have to find another solution there.
If you want to protect yourself from "shoulder surfers" (People who look at your monitor while they pass by), then base64.b64encode("key") and base64.b64decode("a2V5==") should be enough.

Should the program request the key from my server?
Even then a highly motivated (or skilled, or both...) user will be able to get the key by sniffing tools such as Wireshark (if you aren't using https), or even by modifying your script by simply adding a print somewhere.

Do not know the architecture of your code, maybe you can use following architecture:
A -> B -> C
A is your client code, A submit request to B
B is proxy code which is on your private server, and already coding your api_key in the B code, the B code will transfer your A request with the api_key to C
C is the external service
Then, the client code will never record the api key, the api key will be on your private server, this is something like proxy design pattern.
Of course, if you do not want so complex, you can just use Py2exe to package your python code to exe, this is another option, FYI.

Related

PyModbus - trigger an action/function when holding register is read

I've setup a running Pymodbus server based on the 'Updating Server' (v2.5.3) example.
https://pymodbus.readthedocs.io/en/v2.5.3/source/example/updating_server.html
Everything works ok.
Now i want to trigger a function (which will simply increment a value by 1), when (any) client is requesting to read/poll the contents of the holdingregisters.
Console output, when client requests function code 3
My knowledge of Pymodbus is limited, so any help would be great.
There is likely a way to overload the StartTCPServer function, though looking through the source code it seems tricky since it's built on asyncio (not like that's bad, just less conducive to easily overloading this one thing you're trying to do).
However there are several modbus libraries you can use, and sourceperl's pyModbusTCP makes it very easy to do exactly what you're trying to do. Check out the example https://github.com/sourceperl/pyModbusTCP/blob/master/examples/server_change_log.py
There they use the built-in hooks for doing just that, but you can get easily overload any part of the server if you wanted to for example capture the incoming modbus message before it gets processed.

Limit access to a specific file from only a specific Python script in Linux

Problem:
Customer would like to make sure that the script I've developed in Python, running under CentOS7, can sufficiently obscure the credentials required to access a protected web service (that only supports Basic Auth) such that someone with access to the CentOS login cannot determine those credentials.
Discussion:
I have a Python script that needs to run as a specific CentOS user, say "joe".
That script needs to access a protected Web Service.
In order to attempt to make the credentials external to the code I have put them into a configuration file.
I have hidden the file (name starts with a period "."), and base64 encoded the credentials for obscurity, but the requirement is to only allow the Python script to be able to "see" and open the file, vs anyone with access to the CentOS account.
Even though the file is hidden, "joe" can still do an ls -a and see the file, and then cat the contents.
As a possible solution, is there a way to set the file permissions in CentOS such that they will only allow that Python script to see and open the file, but still have the script run under the context of a CentOS account?
Naive solution
For this use-case I would probably create with a script (sh or zsh or whatever, but I guess u use the default one here) a temporal user iamtemporal-and-wontstayafterifinish. Then creating the config file for being able to read ONLY by specifically this user (and none permission for all the others). Read here for the how: https://www.thegeekdiary.com/understanding-basic-file-permissions-and-ownership-in-linux/
Getting harder
If the problem still raises in case someone would have root-rights (for any such reason), then just simply forget everything above, and start planning for a vacation, cuz' this will be a lot longer then anyone would think.
Is not anymore a simple python problem, but needs a different business logic. The best u could do is to implement (at least this credentials handling part) in a low-level language so could handle memory in a customized way and ask for them runtime only, don't store them...
Or maybe if u could limit the scope of this user accesses towards the protected Web Service as u say.
Bonus
Even tho it wasn't explicitly asked, I would discourage you from storing credentials with using a simple base64...
For this purpose a simple solution could be the following one at least (without the knowledge of the whole armada of cryptography):
encrypt the passw with a asymmetric cryptographic algorithm (probably RSA with a huge key
inject the key for decryption as a env var while you have an open ssh session to the remote terminal
ideally u use this key only while u decrypt and send it, afterwards make sure u delete the references to the variables
Sidenote: it's still filled with 'flaws'. If security is really a problem, I would consider changing technology or using some sort of lib that handles these stuff more securely. I would start probably here: Securely Erasing Password in Memory (Python)
Not to mention memory dumps can be read 'easily' (if u know what u are looking for...): https://cyberarms.wordpress.com/2011/11/04/memory-forensics-how-to-pull-passwords-from-a-memory-dump/
So yeah, having a key-server which sends you the private key to decrypt is not enough, if you read these last two web entries...

POST method for webhooks dropbox

I simply want to receive notifications from dropbox that a change has been made. I am currently following this tutorial:
https://www.dropbox.com/developers/reference/webhooks#tutorial
The GET method is done, verification is good.
However, when trying to mimic their implementation of POST, I am struggling because of a few things:
I have no idea what redis_url means in the def_process function of the tutorial.
I can't actually verify if anything is really being sent from dropbox.
Also any advice on how I can debug? I can't print anything from my program since it has to be ran on a site rather than an IDE.
Redis is a key-value store; it's just a way to cache your data throughout your application.
For example, access token that is received after oauth callback is stored:
redis_client.hset('tokens', uid, access_token)
only to be used later in process_user:
token = redis_client.hget('tokens', uid)
(code from https://github.com/dropbox/mdwebhook/blob/master/app.py as suggested by their documentation: https://www.dropbox.com/developers/reference/webhooks#webhooks)
The same goes for per-user delta cursors that are also stored.
However there are plenty of resources how to install Redis, for example:
https://www.digitalocean.com/community/tutorials/how-to-install-and-use-redis
In this case your redis_url would be something like:
"redis://localhost:6379/"
There are also hosted solutions, e.g. http://redistogo.com/
Possible workaround would be to use database for such purpose.
As for debugging, you could use logging facility for Python, it's thread safe and capable of writing output to file stream, it should provide you with plenty information if properly used.
More info here:
https://docs.python.org/2/howto/logging.html

Send string to python script through server

How could I send a string(shell script file name) from an android app to a python program on my pc, and have python execute the script named in said string?
I have the python script done... doThis(./openNetflix) will run the ./openNetflix script, which as you probably guessed opens Netflix.
How do I configure a python server to recieve a string and pass it to my doThis(scriptNameString) function?
I started writing a bit lengthy comment on this case, but when you are approaching chars limit for a comment it's good to convert it into an answer I guess!
Easiest way to do this task would be with one of many excellent python libraries for creating REST services. My personal favourite is bottle, and implementing this type of service in with bottle would be as simple as:
from bottle import route, run, template
#route('/execute/<command>')
def execute(command):
if command == "list_blogs":
// Do something 1
elif command == "format_c":
// Do something 2
run(host='localhost', port=79897)
This will not only provide you with the REST service, but will also put a iron wall between user input and actual execution, so the user input will not get mangled with the file you are trying to execute. Just remember to never use command variable anywhere outside of the if/else.
As you can notice this comes with a weakness - anyone with this link can call those functions and potentially cause denial of service, or maybe even actual damage. This is why it would be nice to have some sort of control and added security, to know that the request was made from valid client.
There are many ways to tackle this issue, i strongly encourage you to have a deeper look into those available. Very simple one would be to store on your server a dict of keys and salts, like that:
salts["here_you_put_random_hash_as_key"] = "and_here_the_salt"
And then you also store the salt and key for this specific client in the clients code. Then when client makes a request he includes his key and a checksum (which consists of md5 made from the command, clients salt key and, for example, current hour) as additional arguments. Then when you receive the request and all 3 variables, you try to create your own checksum using same data (so you pick the salt for client key provided and calculate md5 for that salt, current hour and command coming from the client) and if they match then you know that the request is valid.

How to expose data to zabbix

Here is my goal: I would like to be able to report various metrics to zabbix so that we can display the graphs on a web page.
These metrics include:
latency per soap service submission
various query results from one or more databases.
What things do I need to write and/or expose? Or is the zabbix server going to go and get it from an exposed service somewhere?
I've been advised that a script that returns a single value will work, but I'm wondering if that's the right way.
I can offer 2 suggestions to get the metrics into Zabbix:
Use the zabbix_sender binary to feed the data from your script directly to the Zabbix server. This allows your script to call on it's own interval and set all the parameters needed. You really only need to know the location to the zabbix_sender binary. Inside the Zabbix server interface, you would create items with the type of Zabbix trapper. This is the item type which receives values send from the zabbix_sender. You make up the key name and it has to match.
The second way you could do this is to specify a key name and script/binary inside the zabbix_agentd.conf file. Every time the Zabbix server requests this item the script would be called and the data from the script recorded. This allows you to set the intervals in the Zabbix item configuration rather than forcing you to run your script on its own intervals. However, you would need to add this extra bit of information to your zabbix_agentd.conf file for every host.
There may be other ways to do this directly from Python (zabbix_sender bindings for Python maybe?). But these are the 2 ways I have used before which work well. This isn't really Python specific. But you should be able to use zabbix_sender in your Python scripting. Hope this information helps!
Update: I also remembered that Zabbix was working on/has a API (JSON/RPC style). But the documentation site is down at the moment and I am not sure if the API is for submitting item data or not. Here is the Wiki on the API: http://www.zabbix.com/wiki/doc/api
And a project for Python API: https://github.com/gescheit/scripts/tree/master/zabbix/
There seems to be little documentation on the API as it is new as of Zabbix version 1.8
Actually there is a python binding for zabbix_sender. http://pypi.python.org/pypi/zbxsend

Categories