I have created users in mysql with the same password then this code snippet changes the plain text passwords to a hash using bcrypt. Why is the hash different for the same string?
import mysql.connector
import bcrypt
mydb = mysql.connector.connect(
host="localhost",
user="root",
password="........",
database="briandb",
)
mycursor = mydb.cursor()
for user in ["bob", "alice"]:
password = "ttt"
print(password)
hashed = bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt())
print(hashed)
mycursor.execute(
f'UPDATE users set password = "{hashed}" where user = "{user}"'
)
mydb.commit()
You've discovered a key feature of robust password hashing: Each time you hash a password you get a different result. Why?
A different random salt (from bcrypt.gensalt() here) is used each time.
Why is this important?
If a cybercreep breaks into your system and steals your users table, they'll have your salted hashed passwords. When the hashing is done correctly, it is very difficult to recover the unsalted passwords. If they, next, break into a bank's system and steal their hashed passwords, we don't want them to be able to conclude that certain users have the same password on both systems. If they could guess that, they'd know which users to target for deeper cybercrimes.
Related
I am currently working on a password saving application using tkinter, and I don't want the database to be visible/accesible from the computer's local storage. Is there a way to achieve this with a pre-existing python library, or do I have to pay for a service?
You can try encrypting your database. I'm fairly sure sqlite doesn't offer encryption by default, you might need an extension like SQLCipher.
If you are looking for a password verification system, you could use one-way hashes like Sha256 or a salted algorithm. If you need a password manager, you could use PyCryptoDomex to encrypt the user's password with a "master key" that the user has to remember. Then when you want to fetch a passcode, ask them for the master key again and use it to decrypt the password.
you can use Sqlite3En package or SQLCipher
Sqlite3En doc:
https://github.com/yous1010/Sqlite3En_python/tree/master
SQLCipher :
https://www.zetetic.net/sqlcipher/
A simple example for sqlite3En :
To Encript db :
from Sqlite3En import Sqlite3En
Sqlite3En.Encrypt_existing_DB_By_Password('DBfile1\\' , 'DBName.db' ,'Table_Name' , password = 'password' ) #DBfile1\\ is DB path folder
To open and connect Encrypted DB :
Memory_conn = sqlite3.connect(":memory:")
Sqlite3En.Open_Encrypted_DB_By_Password ('DBfile1\\','DBName.db','Table_Name',Memory_conn , password = 'password' )
now you can use sqlite db as usual
to select data :
Memory_conn.execute("SELECT * FROM Table_Name)
To insert new value in DB:
Memory_conn.execute("INSERT INTO Table_Name (ID,NAME,AGE) VALUES (1, 'sam', 35)");
Memory_conn.commit()
Sqlite3En.Save_Change_On_EnDB_By_Password(Memory_conn,'DBName.db','Table_Name','DBfile1\\',password = 'password' )
user_password = 'admin'
salt = bcrypt.gensalt(rounds=16)
password = bcrypt.hashpw(user_password.encode('utf-8'), salt)
print(password)
sql_statementInsert = "INSERT into users
(crypted_password,login,uuid,external_login,external_identity_provider,external_id,is_root,onboarded,hash_method,active,name)
values ('{}','cosmin','1ea2ad82-b07c-11ea-b3de-0242ac130004','cosmin','sonarqube','user',false,true,'BCRYPT',true,'cosmin') on conflict (login) do nothing;".format(password.decode("utf-8"))
The generated hash for this example is: $2b$08$1KDDzD5DoVOEopOWUb0Rbu8A0FtYtI02BopFoY4Qxp5URuf3KA0s2.
I have this code which is generating some hash based on the user_password, but when trying to log in with "admin" value is not working. But when I am inserting directly the following hash in the crypted_password is working: $2a$12$uCkkXmhW5ThVK8mpBvnXOOJRLd64LJeHTeCkSuB3lfaR2N0AYBaSi
Solved this by using the good library, I needed py-bcrypt, the wrong one was bcrypt only. Also if you use the new lib you don't need to decode the password when you insert it.
I am trying to understand how should I use argon2_cffi to store hashed passwords in my database.
Specifically, I am using this code to write the hashed password into my PostgreSQL table.
from argon2 import PasswordHasher
ph = PasswordHasher()
new_user = User(
name=POST.get('name', 'default_value'),
fullname=POST.get('fullname', 'default_value'),
nickname=POST.get('nickname', 'default_value'),
hashed_password=ph.hash(POST.get('password', 'default_value')))
session.add(new_user)
However, this produces a different password everytime the user inserts a password in my form, although the inserted text is the same.
Of course, I know this is he correct behaviour, but what should I do in order to verify that a given registered user has inserted the right password if I cannot produce the same hash?
Sorry, found out myself in the docs...
import argon2
ph = argon2.PasswordHasher()
def login(db, user, password):
hash = db.get_password_hash_for_user(user)
# Verify password, raises exception if wrong.
ph.verify(hash, password)
# Now that we have the cleartext password,
# check the hash's parameters and if outdated,
# rehash the user's password in the database.
if ph.check_needs_rehash(hash):
db.set_password_hash_for_user(user, ph.hash(password))
I like to create a secure login with Python but need to check the user table from a database, so that multiple users can log in with their own password.
Mainly like this, works like a charm but not secured of course.
while True:
USER = input("User: ")
PASSWORD = getpass.getpass()
db = sqlite3.connect("test.db")
c = db.cursor()
login = c.execute("SELECT * from LOGIN WHERE USER = ? AND PASSWORD = ?", (USER, PASSWORD))
if (len(login.fetchall()) > 0):
print()
print("Welcome")
break
else:
print("Login Failed")
continue
So then I tried hashing the password, work also of course, but then I can't store it on the database to check, so there is no check at all.
from passlib.hash import sha256_crypt
password = input("Password: ")
hash1 = sha256_crypt.encrypt( password )
hash2 = sha256_crypt.encrypt( password )
print(hash1)
print(hash2)
import getpass
from passlib.hash import sha256_crypt
passwd = getpass.getpass("Please enter the secret password: ")
if sha256_crypt.verify( passwd, hash ):
print("Everything worked!")
else:
print("Try again :(")
I tried like this so that the password hash would be taken from the database but with no success:
USER = input("User: ")
db = sqlite3.connect("test.db")
c = db.cursor()
hash = "SELECT HASH FROM LOGIN WHERE USER = %s"%USER
print(hash)
passwd = getpass.getpass("Password: ")
if sha256_crypt.verify( passwd, hash ):
print("Everything worked!")
else:
print("Try again :(")
So my question is, what is the best way to create a secure login for my program? And I do need different logins for different users as stated in the user table. I did it on MySQL before but for testing purpose I'm now trying on sql3. So that doesn't matter. As long as I know how to approach this.
Really you should avoid doing this yourself at all. There are plenty of libraries that correctly implement this kind of authentication.
Nevertheless, the pattern to follow is like this:
Don't store the plain password in the database at all. When the user account is created, hash the password immediately and store that.
When the user logs in, hash the value they enter for the password, then compare that against the value stored in the database already.
(Note that for decent security, you not only need to use a modern hash algorithm but should also use a salt).
I have a table named 'staff', with several columns, but the two I'm interested in are 'username' and 'password'. I am trying to create a prompt which asks the user for their username (and later I will do password) and checks the table in the database to see if that username exists. I am a bit clueless about how to do this, but this is what I have coded so far.
import MySQLdb
db = MySQLdb.connect(host="127.0.0.1", user="root", passwd="", db="sakila")
cur = db.cursor()
search = raw_input("Enter username: ")
query = ('SELECT username, password FROM staff')
cur.execute(query)
results = cur.fetchall()
if search in results:
print("username found")
else:
print("invalid username")
db.close()
EDIT: Make sure to check the comment from #FallenAngel at the bottom and check for security risks in your code!
As Gordon mentioned, you should use a WHERE clause to make things easier. Like so:
import re
import MySQLdb
db = MySQLdb.connect(host="127.0.0.1", user="root", passwd="", db="sakila")
cur = db.cursor()
search = raw_input("Enter username: ")
user_regex = # input a regex here to make sure the username matches a format which avoids SQL injection.
if re.search(user_regex, search):
query = ("SELECT password FROM staff WHERE username = %s", (search,)) # add a WHERE clause
cur.execute(query)
results = cur.fetchall()
else:
results = None
if results: # Now we just need to check if the queryset is empty or not.
print("username found")
else:
print("invalid username")
db.close()
General rule of thumb is to try and make SQL do the searching for things, it's built for it so will be faster than Python.
Make sure your username column is a primary key (or a unique one at least) so you don't have duplicates.
EDIT: Based on #FallenAngels point, you shouldn't directly inject user input into an SQL query as it would expose you to SQL injection.
EDIT2:
First note that we are no longer using "%s" % var formatting for this solution as it is unsafe! Instead we are using "%s", (var,) formatting which is for db queries.
%s (it can also be %d, %n and a few other letters) in a string is a form of string formatting used to insert variable content into a string.
Essentially if you say:
"some stuff here: %s" % var
Anything that is in var will replace the %s in the string. There are several intricacies so it's worth reading more here: https://docs.python.org/2/library/string.html
Perhaps you need to distribute this in two files
In first file you please build the form and through app.route you link it to the def in python file.
This way you can have your presentation and business model completely separate and that will remain more maintainable as well.
Please let me know if you need more simplification along with the code.