尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

hikivision 考勤机数据提取

hikivision 考勤机数据提取
📅 发布时间:2026/6/20 4:24:27

海康的某考勤机可以根据网上的 api 接口提取数据,而不必用优盘拷贝。
经过观察,有如下的流程——

graph TDA[开始] --> B[Step 1: GET sessionLogin/capabilities with random]B --> C[Step 2: POST sessionLogin with timestamp]C --> D[Step 3: PUT sessionHeartbeat]D --> E[Step 4: GET Security/capabilities]E --> F[Step 5: 计算固定AES密钥]F --> G[Step 6: GET Security/users 验证密钥]G --> H[Step 7: POST AcsEvent 获取数据]H --> I[Step 8: AES-CBC + Base64 解密]I --> J[保存为CSV或JSON]J --> K[结束]

考勤等数据存在 AES CBC 加密和 Base64 编码。
aes key是固定不变的,可以调试得到(或者由固定的盐值按算法计算而来)
image
image
image

image
searchId 可以选择某个固定的值,或者使用 uuidv4

image
image

#!/usr/bin/env python3
"""
Hikvision Attendance Data Extractor (Cleaned & Enhanced)
- Uses fixed AES key
- Splits ISO8601 time into 'date' and 'time' (HH:MM:SS)
- Removes redundant comments/logic
"""import json
import binascii
import base64
import hashlib
import time
import re
import requests
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad# ------------------- Config -------------------
HOST = "192.168.1.192"
USERNAME = "admin"
PASSWORD = "password"
BASE_URL = f"http://{HOST}"
AES_KEY = "90c5ba363d3a4d7db66d2564c5697319"  # 32 hex chars = 16 bytessession = requests.Session()# ------------------- Auth -------------------
def login():# Step 1: Get session challengerandom_param = str(int(hashlib.md5(str(time.time()).encode()).hexdigest()[:8], 16))[:8]cap_url = f"{BASE_URL}/ISAPI/Security/sessionLogin/capabilities?username={USERNAME}&random={random_param}"try:resp = session.get(cap_url, timeout=10)resp.raise_for_status()session_id = re.search(r"<sessionID>(\w+)</sessionID>", resp.text).group(1)challenge = re.search(r"<challenge>([a-f0-9]+)</challenge>", resp.text).group(1)iterations = int(re.search(r"<iterations>(\d+)</iterations>", resp.text).group(1))salt = re.search(r"<salt>(\w+)</salt>", resp.text).group(1)except Exception as e:print(json.dumps({"error": f"Get capabilities failed: {e}"}))return None# Step 2: Compute password hashpwd = hashlib.sha256((USERNAME + salt + PASSWORD).encode()).hexdigest()pwd = hashlib.sha256((pwd + challenge).encode()).hexdigest()for _ in range(2, iterations):pwd = hashlib.sha256(pwd.encode()).hexdigest()# Step 3: Loginlogin_xml = f"""<SessionLogin><userName>{USERNAME}</userName><password>{pwd}</password><sessionID>{session_id}</sessionID><isSupportSessionTag>false</isSupportSessionTag><isSessionIDValidLongTerm>false</isSessionIDValidLongTerm><sessionIDVersion>2</sessionIDVersion>
</SessionLogin>"""ts = int(time.time() * 1000)login_url = f"{BASE_URL}/ISAPI/Security/sessionLogin?timeStamp={ts}"try:resp = session.post(login_url, data=login_xml, timeout=10)if "<statusValue>200</statusValue>" not in resp.text:print(json.dumps({"error": "Login failed"}))return Nonereturn tsexcept Exception as e:print(json.dumps({"error": f"Login error: {e}"}))return None# ------------------- Decrypt -------------------
def aes_decrypt_base64(ciphertext_hex, key_hex, iv_hex):if not ciphertext_hex:return ""try:key = binascii.unhexlify(key_hex)iv = binascii.unhexlify(iv_hex)ct = binascii.unhexlify(ciphertext_hex)cipher = AES.new(key, AES.MODE_CBC, iv)decrypted = unpad(cipher.decrypt(ct), AES.block_size)b64_str = decrypted.decode('utf-8')return base64.b64decode(b64_str).decode('utf-8')except Exception:return ciphertext_hex  # fallback to original if decryption fails# ------------------- Fetch -------------------
def fetch_attendance(start_time, end_time, login_ts):iv = hashlib.md5(str(login_ts).encode()).hexdigest()url = f"{BASE_URL}/ISAPI/AccessControl/AcsEvent?format=json&security=1&iv={iv}"records = []position = 0while True:payload = {"AcsEventCond": {"searchID": "c6b8f41a-d75a-4e43-a0c9-8e032f636bb1","searchResultPosition": position,"maxResults": 24,"major": 0,"minor": 0,"startTime": start_time,"endTime": end_time,}}try:resp = session.post(url, json=payload, timeout=30)resp.raise_for_status()data = resp.json()info_list = data.get("AcsEvent", {}).get("InfoList", [])if not info_list:breakfor item in info_list:name_enc = item.get("name", "")emp_enc = item.get("employeeNoString", "")time_raw = item.get("time", "")# Decrypt fields if long (likely encrypted)name = aes_decrypt_base64(name_enc, AES_KEY, iv) if len(name_enc) > 20 else name_encemp_no = aes_decrypt_base64(emp_enc, AES_KEY, iv) if len(emp_enc) > 20 else emp_enc# Split ISO8601 time: "2025-10-09T08:16:09+08:00" → date="2025-10-09", time="08:16:09"date_part = time_part = ""if time_raw:if "T" in time_raw:dt_part = time_raw.split("T")[0]t_part = time_raw.split("T")[1]time_part = t_part.split("+")[0].split(".")[0]  # Remove timezone and millisdate_part = dt_partelse:date_part = time_part = time_rawrecords.append({"employeeNo": emp_no,"name": name,"date": date_part,"time": time_part,"cardNo": item.get("cardNo", "")})position += len(info_list)total = data.get("AcsEvent", {}).get("totalMatches", 0)if position >= total:breakexcept Exception as e:print(json.dumps({"error": f"Fetch error: {e}"}))breakreturn records# ------------------- Main -------------------
def main():login_ts = login()if not login_ts:returnstart = "2025-10-01T00:00:00+08:00"end = "2025-10-31T23:59:59+08:00"records = fetch_attendance(start, end, login_ts)with open("attendance_simple.json", "w", encoding="utf-8") as f:json.dump(records, f, ensure_ascii=False, indent=2)print(f"✅ Successfully saved {len(records)} records to attendance_simple.json")if __name__ == "__main__":main()

参考阅读:

相关新闻

  • [python] Python数据类使用指北
  • 深入解析:iOS 26 App 开发阶段性能优化 从多工具协作到数据驱动的实战体系
  • 小程序开发使用vant ui 组件快速开发

最新新闻

  • 2026年靠谱的上海特种电缆/上海PU电缆优质厂家推荐榜 - 品牌宣传支持者
  • 2026年靠谱的pvc给水管/安徽pvc管/pvc排水管可靠供应商推荐 - 行业平台推荐
  • 2026年口碑好的激光切管/济宁激光切管/激光切管代工/济宁激光切管代工精选厂家推荐 - 品牌宣传支持者
  • 青岛即墨区靠谱的空调清洗公司咨询电话(2026最新) - 品牌排行榜
  • 2026年质量好的医药合规卷筒不干胶/食品包装卷筒不干胶/定制卷筒不干胶厂家哪家好 - 行业平台推荐
  • 2026年可靠的青岛办公工学椅/青岛人体工学椅/工学椅/商务久坐工学椅公司哪家好 - 行业平台推荐

日新闻

  • 信任的进化:技术实现详解——如何用JavaScript构建博弈论模拟器
  • Terrakube自定义工作流:如何集成OPA、Infracost等工具扩展IaC能力
  • grunt-concurrent快速入门:5分钟学会并行运行Grunt任务

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号