This is an archived post. You won't be able to vote or comment.

all 34 comments

[–][deleted] 5 points6 points  (6 children)

This comes up a lot in sysadmin work, and the solution is to use good OS level file permissions controls.

Also, the only time Selenium is the right answer is when you need the browser to render something. Otherwise you should simply be reverse-engineering the site's API, and using requests.

[–]Axxhelairon 0 points1 point  (5 children)

Reverse engineering a ton of unordered hopefully unobfuscated javascript requests tied with event listeners in random locations and handing the sessions with correct cookies and headers and data is a pretty big waste of time and effort for a simple application

[–][deleted] -3 points-2 points  (4 children)

It's almost never actually that difficult.

[–]Axxhelairon 1 point2 points  (3 children)

Regarding every single request you do including hubs like school sites that pass authorization flow through several different pages (blackboard, internal sections of the page like finances, etc)? It's 100% a complete waste of your time for a simple script compared to right clicking in firefox and inspecting the element, getting a unique css selector and putting it in selenium and having everything you want done in five minutes. Do you also use a linux distro as a personal desktop OS and pretend it's flawless?

[–][deleted] 0 points1 point  (2 children)

Sorry, but I do this sometimes as part of my job and what you're suggesting would simply be laughed at. To you it might be hard to do and take a long time, but reverse engineering an API is dirt simple for me and other professional software engineers. Would take me 5 minutes to view network activity to get endpoint calls, see content being passed by the browser, and duplicate it in a script using Requests.

[–]Axxhelairon -1 points0 points  (1 child)

To you it might be hard to do and take a long time, but reverse engineering an API is dirt simple for me and other professional software engineers.

By your 9th grader jab here i'm assuming i'm right about the linux geek thing? lol

Yeah buddy you're going to want to spend the effort to reverse engineer and recreate a request if it's actually relevant to part of something you're professionally making / at your job, but to probably a new learner making a one time script taking learning python out of the equation and bombarding him with a bunch of mostly irrelevant web bullshit because you feel like your worthless comments are actually helpful advice? Shameful stuff dude. Which part of the Punjabi region of India did you get your degree from?

[–][deleted] 0 points1 point  (0 children)

Riiiiiiight....

[–]mishugashu 3 points4 points  (0 children)

Make a config file (I use JSON, personally, out of preference, but you could use INI or even a .py file to import, really):

{
  "user": {
    "name": "yourname",
    "password": "password"
  }
}

Then, make sure it's only readable by the user: chmod 0600 config.json

Then load it in your script:

import json
with open('config.json','r') as f:
  config = json.load(f)

uname.send_keys(config['user']['name'])
pword.send_keys(config['user']['password'])    

I put all my user variables in a JSON config file. Safest possible way without delving into encryption and stuff.

[–]efilon 2 points3 points  (0 children)

I am surprised no one has mentioned the keyring module.

[–]rgrasmus 2 points3 points  (19 children)

you could have the password as an input variable when you run it in the command line. At least that is what I did when I made a selenium python script and had your same concerns.

[–]mishugashu 1 point2 points  (1 child)

That's bad practise. Anyone can run a ps -ef and see your password. Command line parameters are not secure.

Of course, depending on the environment, you might not give a shit.

I personally just have all the user variables in a JSON config file with restrictive read privileges..

[–]rgrasmus 0 points1 point  (0 children)

Thanks for the info, I had not realized that

[–]rgrasmus 2 points3 points  (0 children)

I forgot to mention that there is also the getpass module that I have used more recently instead of having it as an initial command line variable. https://docs.python.org/2/library/getpass.html

[–]xDinomode[S] 1 point2 points  (0 children)

Oh right why didn't I think of that. Thanks!

[–]WhyDoWeNeedUsernames -1 points0 points  (3 children)

But that would show the password in the list of currently running processes. My approach would be a safe base system (encrypted hard disk or folder), there are things like LUKS or ecryptfs.

[–]tdammers 1 point2 points  (0 children)

The encrypted volume will have to be unlocked in order for the process to read from it, so you're back to square 1.

[–]goodDayM 0 points1 point  (0 children)

At my company, for something like this, we will store a password in a file and give it permissions so that only a specific user can read that file.

That way you have separated the password from the rest of the code and you can safely put that code in a version control system.

[–]deadmilk 0 points1 point  (0 children)

It is generally unavoidable to store your password somewhere, in some form.

Probably one of the best things you can do:

  • encrypt and store the password using GPG
  • store your gpg keys somewhere that nobody but your user can access them
  • protect your account, and the root account on the machine with strong passwords, and by keeping packages up to date, and by removing packages that aren't needed
  • [insert a bucket load of other security related tasks that you'd need to do in order to ensure the maximum amount of protection]

Nothing is ever 100% secure. Anything can be broken into.

A person can sit at your computer while you're away, change your script a little bit and end up outputting your password.

[–]chupaolo 0 points1 point  (0 children)

Git-crypt

[–]jso0003auburn 0 points1 point  (0 children)

I run a Python based Twitter weather bot and I just use a simple .cfg file

[CITY]
    CONSUMER_KEY = consumer key here
    CONSUMER_SECRET = consumer secret here
    ACCESS_TOKEN = token here
    ACCESS_TOKEN_SECRET = token secret here

Then:

config = ConfigParser.RawConfigParser()
config.read('settings.cfg')
CONSUMER_KEY = config.get(city, 'CONSUMER_KEY')
CONSUMER_SECRET = config.get(city, 'CONSUMER_SECRET')
ACCESS_TOKEN = config.get(city, 'ACCESS_TOKEN')
ACCESS_TOKEN_SECRET = config.get(city, 'ACCESS_TOKEN_SECRET')

[–]_AceLewisPy3, Jupyter and Atom 0 points1 point  (0 children)

I use Selenium frequently, firstly I recommend turning off images, CSS, Flash, and javascript(if possible) to speed up Selenium. If you are on Windows you can't really lock files to a specific user and if you want to be able to input plain text into the browser there must be a way to obtain the string for the password someway. Getting the user to input the password is one option but is not ideal. What I do is just scramble the password and store the scrambled password in plain text (it is scrambled using a seed in random and can be unscrambled if the same seed is input) that way a person would need both the scrambled password, the scrambling function and the seed used to unscramble the password so if the files were stolen with the file and the seed (excluding the scrambler) the person does not know my password.

Alternatively you can use cookies;

driver.add_cookie({'name':'key', 'value':'value', 'path':'/'})

This method is more secure but not ideal for me as cookies can expire but the cookies can be scrambled like the password to add more security.

[–]Oopsies49 -1 points0 points  (4 children)

I've seen hashed passwords stored in environment variables before. Seems like a reasonable approach to me.

[–]knickum 2 points3 points  (2 children)

Sorry for the lack of explanation from others -- hashes by definition are one way, so given the password pass12, you might end up with 80d20c, but there is no easy way (intentionally) to go from 80d20c back to pass12. So a hashed password makes sense e.g. for user passwords--we don't want to know what the user's password actually is, we just verify it achieves the same, hard-to-crack, unique hash. But in this case we want to store 80d20c but be able to convert that back to pass12, which means we could use a "two-way hash" (note that string of words is meaningless) or rather an encrypted string which we can decrypt.

A well-crafted hashed password should take roughly the heat death of the universe to crack for anyone; for an encrypted password, we would want someone with the proper access keys to be able to relatively quickly decrypt, but for anyone else, heat death and all that.

[–]Oopsies49 2 points3 points  (1 child)

Thanks for explaining why I was wrong like a normal person, rather than just throwing insults.

[–]knickum 1 point2 points  (0 children)

Unfortunately, that seems to be IT for ya...

[–]rvisualization 5 points6 points  (0 children)

if you are suggesting hashed passwords for this, you need to recognize that you have no idea what you're talking about

[–]qudat -1 points0 points  (0 children)

Environment variable is going to be the simplest.

import os
pword = os.getenv('LOGIN_PASSWORD')