加密策略

之前做过的项目用过几种不同的加密方式,总结下

Python

1. 使用werkzeug.security.generate_password_hash

information新闻系统

# 注册用户
# 请求路径: /passport/register
# 请求方式: POST
# 请求参数: mobile, sms_code,password
# 返回值: errno, errmsg
@passport_bp.route('/register', methods=['POST'])
def register():
    # 1.获取参数
    dict_data = request.json
    mobile = dict_data.get('mobile')
    sms_code = dict_data.get('sms_code')
    password = dict_data.get('password')

    # 2.校验参数
    if not all([mobile, sms_code, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不全')

    # 3.手机号作为key取出redis中的短信验证码
    try:
        redis_sms_code = redis_store.get('sms_code:%s'%mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='短信验证码取出失败')

    # 4.判断短信验证码是否过期
    if not redis_sms_code:
        return jsonify(errno=RET.NODATA, errmsg='短信验证码已经过期')

    # 5.判断验证码是否正确
    if sms_code != redis_sms_code:
        return jsonify(errno=RET.DATAERR, errmsg='短信验证码填写错误')

    # 6.删除短信验证码
    try:
        redis_store.delete('sms_code:%s'%mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='短信验证码删除失败')

    # 7. 创建用户对象
    user = User()

    # 8. 设置用户对象属性
    user.nick_name = mobile
    user.password = password
    user.mobile = mobile
    user.signature = '改用户很懒,什么都没写'

    # 9. 保存用户到数据库
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg='用户注册失败')

    # 10. 返回响应
    return jsonify(errno=RET.OK, errmsg='注册成功')
class User(BaseModel, db.Model):
    """用户"""
    __tablename__ = "info_user"

    id = db.Column(db.Integer, primary_key=True)  # 用户编号
    nick_name = db.Column(db.String(32), unique=True, nullable=False)  # 用户昵称
    password_hash = db.Column(db.String(128), nullable=False)  # 加密的密码
    mobile = db.Column(db.String(11), unique=True, nullable=False)  # 手机号
    avatar_url = db.Column(db.String(256))  # 用户头像路径
    last_login = db.Column(db.DateTime, default=datetime.now)  # 最后一次登录时间
    is_admin = db.Column(db.Boolean, default=False)
    signature = db.Column(db.String(512))  # 用户签名
    gender = db.Column(  # 订单的状态
        db.Enum(
            "MAN",  # 男
            "WOMAN"  # 女
        ),
        default="MAN")

    # 当前用户收藏的所有新闻
    collection_news = db.relationship("News", secondary=tb_user_collection, lazy="dynamic")  # 用户收藏的新闻
    # 用户所有的粉丝,添加了反向引用followed,代表用户都关注了哪些人
    followers = db.relationship('User',
                                secondary=tb_user_follows,
                                primaryjoin=id == tb_user_follows.c.followed_id,
                                secondaryjoin=id == tb_user_follows.c.follower_id,
                                backref=db.backref('followed', lazy='dynamic'),
                                lazy='dynamic')

    # 当前用户所发布的新闻
    news_list = db.relationship('News', backref='user', lazy='dynamic')

    @property
    def password(self):
        raise AttributeError("当前属性不可读")

    @password.setter
    def password(self, value):
        self.password_hash = generate_password_hash(value)

    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

    def to_dict(self):
        resp_dict = {
            "id": self.id,
            "nick_name": self.nick_name,
            "avatar_url": constants.QINIU_DOMIN_PREFIX + self.avatar_url if self.avatar_url else "",
            "mobile": self.mobile,
            "gender": self.gender if self.gender else "MAN",
            "signature": self.signature if self.signature else "",
            "followers_count": self.followers.count(),
            "news_count": self.news_list.count()
        }
        return resp_dict

    def to_admin_dict(self):
        resp_dict = {
            "id": self.id,
            "nick_name": self.nick_name,
            "mobile": self.mobile,
            "register": self.create_time.strftime("%Y-%m-%d %H:%M:%S"),
            "last_login": self.last_login.strftime("%Y-%m-%d %H:%M:%S"),
        }
        return resp_dict

titan

    def sign_in(self, password: str) -> str:
        """
        用户登录
        :param password:
        :return:
        """
        if self.is_anonymous:
            raise exceptions.NotFound(message='用户不存在')

        # 密码校检
        check_pw = self.user.validate_password(password)
        if not check_pw:
            raise exceptions.InvalidArgument(message='密码不正确')

        # 更新登录时间
        now = time.time()
        self.user.login_at = now
        self.user_repo.save(self.user)

        token = encode_token(role=self.user.role, id=self.user.id, login_at=self.user.login_at,
                             env=current_app.config['ENV']).decode()

        # 从登出用户缓存列表中删除该用户
        if redis.sismember(SignOutUserListKey, self.user.id):
            redis.srem(SignOutUserListKey, self.user.id)

        auth_token = 'JWT ' + token

        return auth_token

model.py

from typing import List, Optional

from sqlalchemy import BIGINT, VARCHAR, SMALLINT
from sqlalchemy import and_, or_
from sqlalchemy import distinct
from werkzeug.security import generate_password_hash, check_password_hash

class User(BaseObject, psql.Model):
    """
    用户表
    """
    __tablename__ = 'st_user'

    # common fields
    id = psql.Column(VARCHAR(32), autoincrement=False, primary_key=True)
    created_at = psql.Column(BIGINT)
    updated_at = psql.Column(BIGINT)
    deleted_at = psql.Column(BIGINT)  # 如果不为None则该数据已删除

    # flexible information
    login_at = psql.Column(BIGINT)  # 最近登录时间
    name = psql.Column(VARCHAR(128))  # 用户姓名
    phone = psql.Column(VARCHAR(16), unique=True, index=True)  # 用户注册手机号
    password = psql.Column(VARCHAR(128))
    avatar = psql.Column(VARCHAR(256))  # 用户头像URL
    role = psql.Column(SMALLINT)  # 用户角色
    extended_role = psql.Column(SMALLINT)

    # store index, i.e. __table_args__ = (Index("id_idx", id), Index("id_phone_idx", id, phone))
    __table_args__ = ()
    __fields = ('deleted_at', 'password')

    def __init__(self, phone, password, **kwargs):
        super().__init__(**kwargs)
        self.phone = phone
        self.password = self.set_password(password)

    @staticmethod
    def set_password(password):
        return generate_password_hash(password)

    def validate_password(self, password):
        return check_password_hash(self.password, password)

    @staticmethod
    def check_password(hash_, password):  # remove when UserManager works
        return check_password_hash(hash_, password)

2. 加盐salt

order 订餐系统

import hashlib
import base64
import random
import string


class UserService:

    @staticmethod
    def gene_auth_code(user_info):
        """生成授权码"""
        m = hashlib.md5()
        raw_str = "%s-%s-%s-%s" % (user_info.uid, user_info.login_name, user_info.login_pwd, user_info.login_salt)
        m.update(raw_str.encode("utf-8"))
        return m.hexdigest()

    @staticmethod
    def gene_pwd(pwd, salt):
        """密码检验"""
        m = hashlib.md5()
        raw_str = "%s-%s" % (base64.encodebytes(pwd.encode('utf-8')), salt)
        m.update(raw_str.encode("utf-8"))
        return m.hexdigest()

    @staticmethod
    def gene_salt(length=16):
        keys = [random.choice((string.ascii_letters + string.digits)) for _ in range(length)]
        return ("".join(keys))
@route_user.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "GET":
        return ops_render("user/login.html")
    resp = {'code': 200, 'msg': '登陆成功', 'data': {}}
    req = request.values
    login_name = req['login_name'] if 'login_name' in req else ''
    login_pwd = req['login_pwd'] if 'login_pwd' in req else ''

    if login_name is None or len(login_name) < 1:
        resp['code'] = -1
        resp['msg'] = "请输入正确的用户名!"
        return jsonify(resp)

    if login_pwd is None or len(login_pwd) < 1:
        resp['code'] = -1
        resp['msg'] = "请输入正确的密码!"
        return jsonify(resp)

    user_info = User.query.filter_by(login_name=login_name).first()
    if not user_info:
        resp['code'] = -1
        resp['msg'] = "请输入正确的用户名和密码!"
        return jsonify(resp)

    if user_info.login_pwd != UserService.gene_pwd(login_pwd, user_info.login_salt): # 登录密码与加密key
        resp['code'] = -1
        resp['msg'] = "请输入正确的用户名和密码!"
        return jsonify(resp)

    if user_info.status != 1:
        resp['code'] = -1
        resp['msg'] = "账号已被禁用,请联系管理员!"
        return jsonify(resp)

    response = make_response(json.dumps(resp))
    response.set_cookie(app.config['AUTH_COOKIE_NAME'],
                        "%s#%s" % (UserService.gene_auth_code(user_info), user_info.uid))

    return response

Go

1. EncoderSha256

gin_resaurant云餐厅

//用户登录
func (ms *MemberService) Login(name string, password string) *model.Member {

	//1、使用用户名 + 密码 查询用户信息 如果存在用户 直接返回
	md := dao.MemberDao{tool.DbEngine}
	member := md.Query(name, password)
	if member.Id != 0 {
		return member
	}

	//2、用户信息不存在,作为新用户保存到数据库中
	user := model.Member{}
	user.UserName = name
	user.Password = tool.EncoderSha256(password)
	user.RegisterTime = time.Now().Unix()

	result := md.InsertMember(user)
	user.Id = result

	return &user
}
package tool

import (
	"crypto/sha256"
	"encoding/hex"
	"crypto/md5"
	"io"
	"encoding/base64"
	"fmt"
)

func EncoderSha256(data string) string {
	h := sha256.New()
	h.Write([]byte(data))
	sum := h.Sum(nil)

	//由于是十六进制表示,因此需要转换
	s := hex.EncodeToString(sum)
	return string(s)
}

func Md5(data string) string {
	w := md5.New()
	io.WriteString(w, data)
	bydate := w.Sum(nil)
	result := fmt.Sprintf("%x", bydate)
	return result
}

func Base64Encode(data string) string {
	return base64.StdEncoding.EncodeToString([]byte(data))
}
func Base64Decode(data string) ([]byte, error) {
	return base64.StdEncoding.DecodeString(data)
}

2. ScryptPw

ginblog博客系统

package model

import (
	"encoding/base64"
	"ginblog/utils/errmsg"
	"github.com/jinzhu/gorm"
	"golang.org/x/crypto/scrypt"
	"log"
)

type User struct {
	gorm.Model
	Username string `gorm:"type:varchar(20);not null " json:"username" validate:"required,min=4,max=12" label:"用户名"`
	Password string `gorm:"type:varchar(20);not null" json:"password" validate:"required,min=6,max=20" label:"密码"`
	Role     int    `gorm:"type:int;DEFAULT:2" json:"role" validate:"required,gte=2" label:"角色码"`
}

// 新增用户
func CreateUser(data *User) int {
	//data.Password = ScryptPw(data.Password)
	err := db.Create(&data).Error
	if err != nil {
		return errmsg.ERROR // 500
	}
	return errmsg.SUCCSE
}

// 密码加密
func (u *User) BeforeSave() {
	u.Password = ScryptPw(u.Password)
}

func ScryptPw(password string) string {
	const KeyLen = 10
	salt := make([]byte, 8)
	salt = []byte{12, 32, 4, 6, 66, 22, 222, 11}

	HashPw, err := scrypt.Key([]byte(password), salt, 16384, 8, 1, KeyLen)
	if err != nil {
		log.Fatal(err)
	}
	fpw := base64.StdEncoding.EncodeToString(HashPw)
	return fpw
}

3. bcrypt.GenerateFromPassword

package model

import (
	"os"
	"time"

	"github.com/aliyun/aliyun-oss-go-sdk/oss"
	"github.com/jinzhu/gorm"
	"golang.org/x/crypto/bcrypt"
)

// User 用户模型
type User struct {
	gorm.Model
	UserName       string
	PasswordDigest string
	Nickname       string
	Status         string
	Avatar         string `gorm:"size:1000"`
	Sex            string
	Birthday       time.Time
	Sign           string
	Upcnt          uint
}

const (
	// PassWordCost 密码加密难度
	PassWordCost = 12
	// Active 激活用户
	Active string = "active"
	// Inactive 未激活用户
	Inactive string = "inactive"
	// Suspend 被封禁用户
	Suspend string = "suspend"
)

// SetPassword 设置密码
func (user *User) SetPassword(password string) error {
	bytes, err := bcrypt.GenerateFromPassword([]byte(password), PassWordCost)
	if err != nil {
		return err
	}
	user.PasswordDigest = string(bytes)
	return nil
}

// CheckPassword 校验密码
func (user *User) CheckPassword(password string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(user.PasswordDigest), []byte(password))
	return err == nil
}

cookie加密(AesEncrypt)

func (u *UserController) PostLogin() mvc.Response {
	// 由于数据量少,直接通过上下文获取表单中的数据
	userName := u.Ctx.FormValue("userName")
	password := u.Ctx.FormValue("password")
	_, isOK := u.UserService.IsPwdSussess(userName, password)
	if !isOK {
		golog.Error("登陆失败,用户名或密码不正确!")
		return mvc.Response{Path: "/user/login"}
	}
	user, err := u.UserService.GetUserByName(userName)
	if err != nil {
		golog.Error("获取用户信息失败!")
		return mvc.Response{Path: "/user/login"}
	}
	// 将用户id写入Cookie
	tool.GlobalCookie(u.Ctx, "uid", strconv.FormatInt(user.ID, 10), 60*60*24)
	golog.Debug("cookie设置成功!", u.Ctx.GetCookie("uid"))
	// 加uid加密
	uidString, err := encrypt.EnPwdCode([]byte(strconv.FormatInt(user.ID, 10)))
	if err != nil {
		golog.Error("加密失败!", err)
		return mvc.Response{Path: "/user/login"}
	}
	// 将用户加密信息写入Cookie
	tool.GlobalCookie(u.Ctx, "sign", uidString, 60*60*24)
	golog.Debug("登陆成功!")
	return mvc.Response{Path: "/product/detail"}
}
package encrypt

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"errors"
)

//高级加密标准 (Advanced Encryption Standard)AES

//16,24,32位字符串的话,分别对应AES-128,AES-192,AES-256加密方法
//key不能泄漏
var PwdKey=[]byte("DIS**#KKKDJJSKDI")

//PKCS7 填充模式
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padtext...)
}

//填充的反向操作,删除填充字符串
func PKCS7UnPadding(origData []byte) ([]byte, error) {
	length := len(origData)
	if length == 0 {
		return nil, errors.New("加密字符串错误")
	} else {
		padding := int(origData[length-1])
		return origData[:(length - padding)], nil
	}
}

//实现解密
func AesDeCrypt(cypted []byte, key []byte) ([]byte, error) {
	//创建加密算法实例
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	blockSize := block.BlockSize()
	blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
	origData := make([]byte, len(cypted))

	//这个函数也可以用来解密
	blockMode.CryptBlocks(origData, cypted)

	//去除填充字符串
	origData, err = PKCS7UnPadding(origData)
	if err != nil {
		return nil, err
	}

	return origData, nil
}

//实现加密
func AesEncrypt(origData []byte, key []byte) ([]byte, error) {
	//创建加密算法实例
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	//获取块大小
	blockSize := block.BlockSize()
	//对数据进行填充,让数据长度满足需求
	origData = PKCS7Padding(origData, blockSize)
	//采用AES加密方法中CBC加密模式
	blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
	crypted := make([]byte, len(origData))
	blockMode.CryptBlocks(crypted, origData)
	return crypted, nil
}

//加密base64
func EnPwdCode(pwd []byte) (string, error) {
	result, err := AesEncrypt(pwd, PwdKey)
	if err != nil {
		return "", err
	}

	return base64.StdEncoding.EncodeToString(result), err
}

func DePwdCode(pwd string) ([]byte, error) {
	pwdByte, err := base64.StdEncoding.DecodeString(pwd)
	if err != nil {
		return nil, err
	}

	//执行AES解密
	return AesDeCrypt(pwdByte, PwdKey)
}

验证cookie

func CheckUserInfo (r *http.Request) error {
	uidCookie, err := r.Cookie("uid")
	if err != nil {
		return errors.New("用户uid cookie 获取失败!")
	}

	//获取用户加密串
	signCookie, err := r.Cookie("sign")
	if err != nil {
		return errors.New("用户加密串 cookie 获取失败!")
	}

	signStr, err := url.QueryUnescape(signCookie.Value)
	if err != nil {
		return errors.New("url decode 失败")
	}
	signByte, err := encrypt.DePwdCode(signStr)
	if err != nil {
		return errors.New("加密串被篡改")
	}
	if checkInfo(uidCookie.Value , string(signByte)) {
		return nil
	}
	return errors.New("身份校验失败")
}
//统一验证拦截器,每个接口都需要提前验证
func Auth(w http.ResponseWriter, r *http.Request) error {

	err := CheckUserInfo(r)
	if err != nil {
		return errors.New("验证失败")
	}

	return nil
}

对称加密与非对称加密

一:什么是对称加密?

在对称加密算法中,加密和解密使用的是同一把钥匙,即:使用相同的密匙对同一密码进行加密和解密;

加密过程如下:
在这里插入图片描述

例如 jwt.SigningMethodHS256 对称加密

优点:算法简单,加密解密容易,效率高,执行快。
缺点:相对来说不算特别安全,只有一把钥匙,密文如果被拦截,且密钥也被劫持,那么,信息很容易被破译。

二:什么是对称加密?

非对称加密是使用不同的密钥进行加密和解密。

非对称加密有两个钥匙,及公钥(Public Key)和私钥(Private Key)。公钥和私钥是成对的存在,如果对原文使用公钥加密,则只能使用对应的私钥才能解密;因为加密和解密使用的不是同一把密钥,所以这种算法称之为非对称加密算法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值