python授權(quán)加密的幾種常見(jiàn)方案
要讓軟件授權(quán)碼(License Key)更安全,并能限定服務(wù)器和使用時(shí)間,通??梢越Y(jié)合加密、硬件綁定和時(shí)間限制等方式來(lái)增強(qiáng)安全性。以下是幾種常見(jiàn)的方案:
1. 采用非對(duì)稱加密(RSA、ECC)
使用非對(duì)稱加密(如 RSA、ECC)來(lái)生成和驗(yàn)證授權(quán)碼,避免私鑰泄露:
- 生成授權(quán)碼時(shí):服務(wù)器用私鑰加密生成帶有使用時(shí)間和設(shè)備信息的授權(quán)碼;
- 客戶端驗(yàn)證:客戶端軟件用公鑰解密并校驗(yàn)授權(quán)碼的有效性。
示例
- 授權(quán)碼內(nèi)容:
- 用 RSA 私鑰加密并生成授權(quán)碼
- 客戶端用 RSA 公鑰解密并驗(yàn)證有效性
2. 綁定服務(wù)器(機(jī)器)信息
防止授權(quán)碼在多個(gè)設(shè)備上使用,可以綁定 硬件 ID(如 CPU ID、MAC 地址、硬盤(pán)序列號(hào)等)。
- 生成授權(quán)碼時(shí),記錄服務(wù)器的唯一硬件標(biāo)識(shí)
- 客戶端運(yùn)行時(shí)校驗(yàn)當(dāng)前設(shè)備信息是否匹配授權(quán)碼
實(shí)現(xiàn)方法
- 獲取設(shè)備唯一 ID,例如:
- Windows:
wmic cpu get ProcessorId
- Linux:
cat /etc/machine-id
- Windows:
- 生成授權(quán)碼時(shí),把硬件 ID加入授權(quán)信息
- 在客戶端解密授權(quán)碼后比對(duì)當(dāng)前設(shè)備 ID
3. 設(shè)置時(shí)間限制(防止永久使用)
授權(quán)碼應(yīng)包含有效期,并防止用戶篡改系統(tǒng)時(shí)間:
- 在授權(quán)碼中嵌入到期時(shí)間,如
expire: "2025-12-31"
- 服務(wù)器定期驗(yàn)證授權(quán)碼,或者客戶端檢查到期時(shí)間
- 防止修改系統(tǒng)時(shí)間:
- 可使用 NTP 服務(wù)器獲取時(shí)間
- 記錄本地第一次使用的時(shí)間戳,并在下次啟動(dòng)時(shí)對(duì)比是否倒退
4. 使用 HMAC 或?qū)ΨQ加密(AES)防篡改
為了防止授權(quán)碼被篡改,可以使用 HMAC(哈希消息認(rèn)證碼) 或 AES 加密:
- HMAC 方式(SHA256):服務(wù)器用密鑰簽名授權(quán)碼,客戶端驗(yàn)證簽名
- AES 方式:用對(duì)稱密鑰加密整個(gè)授權(quán)碼,客戶端解密后校驗(yàn)
驗(yàn)證授權(quán)碼時(shí),客戶端用相同的 secret_key
計(jì)算簽名并校驗(yàn)。
5. 結(jié)合在線授權(quán)服務(wù)器
為了更安全,可以使用在線授權(quán)服務(wù)器,客戶端每次啟動(dòng)時(shí)需向服務(wù)器驗(yàn)證:
- 授權(quán)服務(wù)器存儲(chǔ)授權(quán)碼和綁定的設(shè)備信息
- 客戶端每次啟動(dòng)時(shí)請(qǐng)求服務(wù)器驗(yàn)證授權(quán)碼
- 服務(wù)器返回結(jié)果,是否授權(quán)、是否過(guò)期、是否被盜用
額外措施:
- 允許離線模式(如本地緩存授權(quán)信息)
- 服務(wù)器可吊銷(xiāo)授權(quán)碼(如檢測(cè)到異常使用)
最佳方案推薦
- 本地校驗(yàn):使用RSA(公私鑰加密)+ HMAC(防篡改)
- 綁定設(shè)備:獲取 CPU ID 或 MAC 地址,存入授權(quán)碼
- 限制時(shí)間:內(nèi)嵌到期時(shí)間,并校驗(yàn)系統(tǒng)時(shí)間防修改
- 服務(wù)器驗(yàn)證(可選):定期檢查授權(quán)碼狀態(tài),支持遠(yuǎn)程吊銷(xiāo)
如果是企業(yè)級(jí)產(chǎn)品,建議采用服務(wù)器+本地加密結(jié)合的方式,避免破解和濫用。
上代碼
管理員:
1.生成公鑰私鑰
import rsa # 生成 2048 位密鑰 (public_key, private_key) = rsa.newkeys(2048) # 保存私鑰(供授權(quán)中心使用) with open("private.pem", "wb") as priv_file: priv_file.write(private_key.save_pkcs1()) # 保存公鑰(供客戶端使用) with open("public.pem", "wb") as pub_file: pub_file.write(public_key.save_pkcs1()) print("RSA 密鑰對(duì)已生成:private.pem(私鑰) 和 public.pem(公鑰)")
2.生成授權(quán)文件
import rsa import json import base64 import os from datetime import datetime # 讀取私鑰 with open("private.pem", "rb") as priv_file: private_key = rsa.PrivateKey.load_pkcs1(priv_file.read()) # 獲取目標(biāo)設(shè)備的 CPU ID # def get_machine_id(): # try: # if os.name == 'nt': # machine_id = os.popen("wmic cpu get ProcessorId").read().split()[1] # print('授權(quán)設(shè)備的唯一標(biāo)識(shí):'+machine_id) # else: # return os.popen("cat /etc/machine-id").read().strip() # except: # return "UNKNOWN" # 生成授權(quán)文件 def generate_license(user, expire_date, machine_id): license_data = { "user": user, "expire": expire_date, "machine_id": machine_id } print(license_data) # 簽名授權(quán)數(shù)據(jù) data_str = f"{user}|{expire_date}|{machine_id}".encode() signature = rsa.sign(data_str, private_key, 'SHA-256') # 添加簽名并保存 JSON license_data["signature"] = base64.b64encode(signature).decode() with open("license.json", "w") as license_file: json.dump(license_data, license_file, indent=4) print("? 授權(quán)文件 license.json 生成成功!") # 示例:為某個(gè)客戶生成授權(quán) generate_license(user="client1", expire_date="2025-12-31", machine_id="機(jī)器碼")
3.授權(quán)文件格式
{ "user": "client1", "expire": "2025-12-31", "machine_id": "BFE***ED", "signature": "R62******8/w==" }
4.要被授權(quán)控制的軟件
import os import time import threading import json import tkinter as tk from tkinter import messagebox, ttk from datetime import datetime import boto3 import configparser from elasticsearch import Elasticsearch from urllib3.exceptions import InsecureRequestWarning import warnings import base64 import logging # 添加 logging 模塊 import rsa import hashlib from botocore.exceptions import ClientError, EndpointConnectionError warnings.filterwarnings("ignore", category=InsecureRequestWarning) # ==================== 配置日志 ==================== logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', filename=f'logs/file_search_{datetime.now().strftime("%Y%m%d_%H%M%S")}.log', filemode='w' ) logger = logging.getLogger(__name__) # ==================== 授權(quán)管理 ==================== LICENSE_FILE = "license.json" PUBLIC_KEY_FILE = "public.pem" def get_machine_id(): """ 獲取當(dāng)前設(shè)備的唯一標(biāo)識(shí)(CPU ID)""" try: if os.name == 'nt': machine_id = os.popen("wmic cpu get ProcessorId").read().split()[1] print('獲取當(dāng)前設(shè)備的唯一標(biāo)識(shí):'+machine_id) return machine_id else: return os.popen("cat /etc/machine-id").read().strip() except: return "UNKNOWN" def load_rsa_public_key(): """ 加載 RSA 公鑰 """ try: with open(PUBLIC_KEY_FILE, "rb") as f: return rsa.PublicKey.load_pkcs1(f.read()) except Exception as e: logger.error(f"無(wú)法加載公鑰: {e}") messagebox.showerror("授權(quán)錯(cuò)誤", "授權(quán)系統(tǒng)異常,無(wú)法加載公鑰") exit(1) def verify_license(): """ 驗(yàn)證授權(quán)碼 """ if not os.path.exists(LICENSE_FILE): messagebox.showerror("授權(quán)錯(cuò)誤", "未找到授權(quán)文件,請(qǐng)聯(lián)系管理員") exit(1) try: with open(LICENSE_FILE, "r") as f: license_data = json.load(f) user = license_data.get("user") expire = license_data.get("expire") machine_id = license_data.get("machine_id") signature = base64.b64decode(license_data.get("signature")) if not all([user, expire, machine_id, signature]): messagebox.showerror("授權(quán)錯(cuò)誤", "授權(quán)文件損壞") exit(1) # 校驗(yàn)過(guò)期時(shí)間 if datetime.strptime(expire, "%Y-%m-%d") < datetime.now(): messagebox.showerror("授權(quán)錯(cuò)誤", "授權(quán)已過(guò)期,請(qǐng)聯(lián)系管理員續(xù)費(fèi)") exit(1) # 校驗(yàn)機(jī)器碼 if machine_id != get_machine_id(): print(machine_id) print(get_machine_id()) messagebox.showerror("授權(quán)錯(cuò)誤", "設(shè)備不匹配,授權(quán)無(wú)效") exit(1) # 驗(yàn)證簽名 public_key = load_rsa_public_key() data_str = f"{user}|{expire}|{machine_id}".encode() try: rsa.verify(data_str, signature, public_key) except rsa.VerificationError: messagebox.showerror("授權(quán)錯(cuò)誤", "授權(quán)碼無(wú)效或被篡改") exit(1) logger.info("授權(quán)驗(yàn)證成功") except Exception as e: logger.error(f"授權(quán)驗(yàn)證失敗: {e}") messagebox.showerror("授權(quán)錯(cuò)誤", "授權(quán)文件無(wú)效") exit(1)
5.將公鑰和授權(quán)json文件放在要授權(quán)的程序下
6.運(yùn)行效果
python main.py
獲取當(dāng)前設(shè)備的唯一標(biāo)識(shí):178B****F10
7.修改授權(quán)文件任性信息授權(quán)報(bào)錯(cuò)
到此這篇關(guān)于python授權(quán)加密的文章就介紹到這了,更多相關(guān)python授權(quán)加密內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 深入理解Python密碼學(xué)之使用PyCrypto庫(kù)進(jìn)行加密和解密
- python如何使用base加密解密
- 使用Cython加密Python代碼防止反編譯
- Python中Cryptography庫(kù)實(shí)現(xiàn)加密解密
- python庫(kù)pycryptodom加密技術(shù)探索(公鑰加密私鑰加密)
- Python hashlib庫(kù)數(shù)據(jù)安全加密必備指南
- python中pycryptodome模塊實(shí)現(xiàn)加密算法庫(kù)
- python實(shí)現(xiàn)aes加密及pycryptodome庫(kù)使用
- 如何用Python實(shí)現(xiàn)RSA加密算法
- python加密打包程序詳解
相關(guān)文章
Docker部署Python爬蟲(chóng)項(xiàng)目的方法步驟
這篇文章主要介紹了Docker部署Python爬蟲(chóng)項(xiàng)目的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01WxPython開(kāi)發(fā)之實(shí)現(xiàn)表格數(shù)據(jù)導(dǎo)出到Excel并打開(kāi)
在 Python 中使用 wxPython 導(dǎo)出實(shí)體類(lèi)列表數(shù)據(jù)到 Excel,通??梢越柚?nbsp;openpyxl 或 pandas 庫(kù)來(lái)實(shí)現(xiàn),下面就跟隨小編一起來(lái)了解下具體操作吧2024-12-12一個(gè)計(jì)算身份證號(hào)碼校驗(yàn)位的Python小程序
閑著無(wú)事,便想寫(xiě)個(gè)實(shí)用點(diǎn)的Python小程序,如何計(jì)算機(jī)身份證號(hào)碼的校驗(yàn)位,這樣的文章在網(wǎng)上一抓一大把,這里僅簡(jiǎn)單介紹下吧2014-08-08跟老齊學(xué)Python之再深點(diǎn),更懂list
對(duì)于list,由于她的確非常非常龐雜,在python中應(yīng)用非常廣泛,所以,雖然已經(jīng)介紹完畢了基礎(chǔ)內(nèi)容,這里還要用一講深入一點(diǎn)點(diǎn),往往越深入越...2014-09-09OpenCV中Canny邊緣檢測(cè)的實(shí)現(xiàn)
本文主要介紹了OpenCV中Canny邊緣檢測(cè)的實(shí)現(xiàn),邊緣檢測(cè)一般是識(shí)別目標(biāo)圖像中亮度變化明顯的像素點(diǎn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07如何用定值 Cookie 實(shí)現(xiàn)反爬詳解
這篇文章主要為大家介紹了如何用定值 Cookie 實(shí)現(xiàn)反爬示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04Python 實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)中的的棧隊(duì)列
這篇文章主要介紹了Python 實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)中的的棧,隊(duì)列,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-05-05python?pandas分割DataFrame中的字符串及元組的方法實(shí)現(xiàn)
本文主要介紹了python?pandas分割DataFrame中的字符串及元組的方法實(shí)現(xiàn),主要介紹了3種方法,具有一定的參考價(jià)值,感興趣的可以了解一下2022-03-03Python中unittest的數(shù)據(jù)驅(qū)動(dòng)詳解
這篇文章主要介紹了Python中unittest的數(shù)據(jù)驅(qū)動(dòng)詳解,數(shù)據(jù)驅(qū)動(dòng)測(cè)試,是一種單元測(cè)試框架,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08python的xpath獲取div標(biāo)簽內(nèi)html內(nèi)容,實(shí)現(xiàn)innerhtml功能的方法
今天小編就為大家分享一篇python的xpath獲取div標(biāo)簽內(nèi)html內(nèi)容,實(shí)現(xiàn)innerhtml功能的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-01-01