我在SQL中使用PASSWORD
来哈希用户密码。
sql = text('insert into account values("%s", "%s", "%s", PASSWORD("%s"), "1" )'%(fname, lname, user_name, password))
当我尝试使用密码登录时,它不允许我访问该帐户。
sql = text('select * from account where account.user_name = "%s" and account.password = PASSWORD("%s") and account.active = ' + '"' + '1' + '"')%(user_name, password)
我收到错误:
unsupported operand type(s) for %: 'TextClause' and 'tuple'
尝试访问加密密码时,我做错了什么?
答案 0 :(得分:11)
立即错误是在第一个示例中,您在字符串上使用了字符串格式%
,然后将结果包含在text
中,而第二个尝试将在text
对象上使用字符串格式。
更严重的问题是您通过直接将用户输入格式化为SQL字符串而不是单独传递它们来打开注入攻击。
看起来您正在使用Flask-SQLAlchemy。在这种情况下,请编写参数化查询并将要正确转义的参数传递给execute
。
db.engine.execute(
'insert into account values(?, ?, ?, PASSWORD(?), ?)',
(fname, lname, user_name, password, True)
)
db.engine.execute(
'select * from account where account.user_name = ? and account.password = PASSWORD(?) and account.active = ?,
(user_name, password, True)
)
参数化概念与任何其他数据库驱动程序类似。
使用passlib
库不是依靠数据库来散列密码,而是一种更强大的替代方案。它包含更强大的哈希值,以及“弃用”的能力。哈希并升级储值。
from passlib.hash import pbkdf2_sha512
# when creating a user, generate the hash with passlib
# and don't use PASSWORD() in SQL
password = pbkdf2_sha512.encrypt('secret')
# example login
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
r = engine.execute('select * from account where account.name = ? and account.active = ?', (username, True))
if r:
user = r[0]
# verify the hash using passlib, not SQL
if pbkdf2_sha512.verify(password, user.password):
# active user, correct password, do the login
return 'good credentials'
# incorrect username or password
return 'bad credentials'
return render_template('login.html')
传入这些哈希值,而不是在SQL中调用PASSWORD
。