这是 proper/secure 登录方式吗?

Is this a proper/secure way to log someone in?

好吧,我真的是编程新手(刚刚学会了如何建立数据库连接,write/read 今天从中学到了),我正在尝试制作一个允许用户登录的基本站点,并且在用户登录时有一些不同的页面。我决定使用 Flask,Flask-session,Sqlite3 进行尝试,基本上身份验证如下:用户使用表单登录,检查表单数据对照sqlite3数据库中的信息,如果正确,则将相应的值写入客户端cookie。这是一种可接受的登录方式吗?请原谅我的无知,但我真的是编程新手,我缺少一些关键术语来在这里寻找我自己的答案。我四处搜索,但无法确定这是否是一种可接受的方式 logins/out。

我的网站可以正常运行,但我不知道我是否真的在传统意义上登录或注销任何内容。还要注意一些路线被奇怪地破坏或隐藏,这只是因为我试图破坏事物以查看它们是如何工作的。要获取我的网站 运行,我没有包含模板:

from app.py import init_db

init_db()

python app.py

这是我的应用程序文件:

#importations
import sqlite3
from flask import Flask, request, session, g, redirect, url_for, \
abort, render_template, flash, escape
from contextlib import closing
import sys
import datetime
from models import User
from formms import RegistrationForm, Login
import os


key1 = os.urandom(24)
#config
DATABASE = '/tmp/fitty1.db'
DEBUG = True
SECRET_KEY = key1
USERNAME = 'admin'
PASSWORD = 'default'
print key1

#Initialize the application
app = Flask(__name__)
app.config.from_object(__name__)

#login_manager = LoginManager()
#login_manager.init_app(app)




#Method to connect to database, use to open a connection on request, or from interactive python shell
def connect_db():
    return sqlite3.connect(app.config['DATABASE'])

#Run this before application to initialize the DB
def init_db():
    with closing(connect_db()) as db:
        with app.open_resource('schema.sql', mode='r') as f:
            db.cursor().executescript(f.read())
        db.commit()


def query_db(query, args=(), one=False):
    cur = get_db().execute(query, args)
    rv = cur.fetchall()
    cur.close()
    return (rv[0] if rv else None) if one else rv



@app.teardown_request
def teardown_request(exception):
    db = getattr(g, 'db', None)
    if db is not None:
        db.close()

@app.route('/')
def show_entries():
    g.db = connect_db()
    cur = g.db.execute('select title, text from entries order by id desc')
    entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()]
    return render_template('show_entries.html', entries=entries)


@app.route('/register', methods=['POST', 'GET'])
def register():
    g.db = connect_db()
    form = RegistrationForm(request.form)
    if request.method == 'POST' and form.validate():
        user = User(form.username.data, form.email.data, form.password.data)
        g.db.execute('insert into users (username, email, password) values (?, ?, ?)',
             [request.form['username'], request.form['email'], request.form['password']])
        g.db.commit()
        flash('Registered successfully')
        return redirect(url_for('show_entries'))
    return render_template('register.html', form=form)


@app.route('/account') 
def account():
    g.db = connect_db()
    if not session.get('logged_in'):
        abort(401)
    if 'username' in session:
        username = session['username']
        c = g.db.execute("SELECT password from users where username = (?)", (username,))
        passwc = c.fetchone()
        c = g.db.execute("SELECT text from entries")
        texty = c.fetchone()
        return 'Your username is "%s", your password is "%s" and code %s' % (username, passwc[0], texty[0])
    return 'You are not logged in'


@app.route('/add', methods=['POST'])
def add_entry():
    g.db = connect_db()
    if not session.get('logged_in'):
        abort(401)
    g.db.execute('insert into entries (title, text) values (?, ?)',
                 [request.form['title'], request.form['text']])
    g.db.commit()
    flash('New entry was successfully added')
    return redirect(url_for('show_entries'))

@app.route('/login', methods=['GET', 'POST'])
def login():
    g.db = connect_db()
    error = None
    form = Login(request.form)
    user = User(form.username.data, form.email.data, form.password.data)
    if request.method == 'POST':
        c = g.db.execute("SELECT username from users where username = (?)", [form.username.data])
        userexists = c.fetchone()
        if userexists:
            c = g.db.execute("SELECT password from users where password = (?)", [form.password.data])
            passwcorrect = c.fetchone()
            if passwcorrect:
                session['username'] = form.username.data
                session['logged_in'] = True
                flash('You were logged in')
                return redirect(url_for('account'))
            else:
                return 'password fail'
        else:
            return 'username fail'
    return render_template('login.html', form=form)


@app.route('/logout')
def logout():
    g.db = connect_db()
    session.pop('logged_in', None)
    flash('You were logged Out')
    return redirect(url_for('show_entries'))




#Use build in server to run standalone application
if __name__ == '__main__':
    app.run()

型号

import sqlite3
from flask import g
from flask.ext.login import LoginManager, login_required

class User():
    def __init__(self,username,email,password,active=True):
        self.username = username
        self.email = email
        self.password = password
        self.active = active

    def is_authenticated(self):
        return True
        #Return true if authenticated, provided credentials

    def is_active(self):
        return True

def is_anonymous(self):
    return False
    #return true if anon, actual user returns false


def __repr__(self):
    return '<User %r>' % (self.email)

Schema.sql

drop table if exists entries;
create table entries (
  id integer primary key autoincrement,
  title text not null,
  text text not null
);
drop table if exists users;
create table users (
  id integer primary key autoincrement,
  username text not null,
  email text not null,
  password text not null
);

这绝对是正确的做法。客户端 cookie 允许您唯一地识别用户。您只需要确保 cookie 足够随机,否则有人可能会欺骗它。

如果你给我的 cookie 是 uid=hailey 那会很糟糕,因为我可以轻松地将其编辑为 uid=ach1lles 并获得你的管理员权限。相反,您想做一些足够随机的事情,例如我的用户名和当前时间的 sha2 哈希的 base64 以及昨天 NYT 的标题或类似的疯狂事情。您可能希望将其添加为数据库 table,然后在我发出请求时检查它。

此外,不要将密码存储为文本,考虑像 bcrypt 这样的东西。 :)

您的第二个 SELECT 查询存在安全风险。只要知道任何一个用户的密码,就可以以任何用户身份登录。

假设您有以下用户(忽略密码是明文):

username | password
---------+---------
Jack     | abc123
-------------------
Jill     | def456

假设有人尝试使用 "Jack" 作为用户名和 "def456" 作为密码登录。

你的第一个SELECT

c = g.db.execute("SELECT username from users where username = (?)", [form.username.data])

将 return 打破杰克的记录。这会导致您执行第二个 SELECT

c = g.db.execute("SELECT password from users where password = (?)", [form.password.data])

这将打破 return 吉尔的记录。虽然这是不同的用户,但您只检查查询中的 return 记录,而不是与第一个查询相同的记录。即使输入错误的 Jack 密码,用户仍将以 Jack 身份登录。

理想情况下,您只想根据用户名执行一次查询,并将提交的密码与数据库中的密码进行比较。

c = g.db.execute("SELECT username, password from users where username = (?)", [form.username.data])
user = c.fetchone()
# don't forget to apply your hashing algorithm to form.password.data
if user and user[1] == form.password.data:  
    session['username'] = form.username.data
    session['logged_in'] = True
    flash('You were logged in')
    return redirect(url_for('account'))

综上所述,我对 Flask-Login and Flask-Security 这样的库的推荐再多也不为过。身份验证很难正确。利用社区让它变得更容易。