Linux 日志时间解析:journalctl 查看完整时间戳

syslog 格式的日志默认不记录年份,看到 Nov 15 13:57:05 无法确认是哪一年。 显示完整年份(ISO 格式) journalctl -u your-service -o short-iso输出示例: 2025-11-15T13:57:05+08:00 hostname service: log message-o short-iso 输出 ISO 8601 格式,包含年份和时区。 按时间范围过滤 journalctl -u your-service \ --since "2025-11-15 13:52:00" \ --until "2025-11-15 14:02:00"查看最近 N 分钟: journalctl -u your-service --since "10 minutes ago"实时跟踪(类似 tail -f): journalctl -u your-service -f查找错误并显示上下文 已知有一条错误日志,想看前后发生了什么: # 找到行号 journalctl -u your-service | grep -n "错误关键字"# 查看前后 50 行 journalctl -u your-service -n 1000 | grep -C 50 "错误关键字"-C 50 = Context 50,显示匹配行前后各 50 行。 普通日志文件的上下文查询 日志在 /opt/logs/app.log: # 找到行号 grep -n "错误关键字" /opt/logs/app.log# 例如输出: 123456:错误关键字 # 查看附近 100 行 sed -n '123400,123500p' /opt/logs/app.log或者直接用 -C 参数: grep -nC 50 "错误关键字" /opt/logs/app.log定位 Java 服务的真实错误原因 Java 的 查询简单视图数据失败 这类消息通常只是表层日志,真正原因在下面的 Caused by:: # 先找到关键字附近 grep -C 100 "查询简单视图数据失败" app.log | grep "Caused by"常见真实原因:Caused by: java.sql.SQLException — SQL 执行失败 Caused by: org.springframework.data.redis.RedisConnectionFailureException — Redis 连接断开 Caused by: feign.RetryableException — 上游服务不可达找到 Caused by 后再针对异常类型排查。 大日志文件的搜索技巧 # 只看有关键字的行(不展示上下文) grep "关键字" /var/log/app.log | tail -20# 统计出现次数 grep -c "ERROR" /var/log/app.log# 按时间段提取(前提:日志每行以时间开头) awk '/2025-11-15 13:5[0-9]/' /var/log/app.logjournalctl 常用参数速查 journalctl -u <service> # 指定服务 journalctl -u <service> -n 100 # 最新 100 行 journalctl -u <service> -f # 实时跟踪 journalctl -u <service> -o short-iso # ISO 时间戳(含年份) journalctl -u <service> -p err # 只看 error 级别 journalctl --since "1 hour ago" # 最近 1 小时 journalctl --disk-usage # 日志占用磁盘 journalctl --vacuum-time=7d # 清理 7 天前日志

Python 实现 PBKDF2 + AES-256-GCM 加密存储

PBKDF2 + AES-GCM 是本地加密存储(钱包 vault、配置文件保护)的标准方案:密码经 PBKDF2 派生出密钥,AES-GCM 提供加密和完整性验证。 加密流程 Password ↓ PBKDF2-HMAC-SHA512(iterations=600000, salt=随机16字节) ↓ 32 字节 AES Key ↓ AES-256-GCM(nonce=随机16字节) ↓ Ciphertext + Tag安装依赖 pip install pycryptodome完整实现 import json import os import base64 from hashlib import pbkdf2_hmac from Crypto.Cipher import AESPBKDF2_ITERATIONS = 600_000 # NIST 2023 推荐最低值def derive_key(password: str, salt: bytes) -> bytes: return pbkdf2_hmac( "sha512", password.encode("utf-8"), salt, PBKDF2_ITERATIONS, dklen=32, # AES-256 )def encrypt(password: str, plaintext: str) -> dict: salt = os.urandom(16) nonce = os.urandom(16) key = derive_key(password, salt) cipher = AES.new(key, AES.MODE_GCM, nonce=nonce) ciphertext, tag = cipher.encrypt_and_digest(plaintext.encode("utf-8")) return { "salt": base64.b64encode(salt).decode(), "nonce": base64.b64encode(nonce).decode(), "ciphertext": base64.b64encode(ciphertext).decode(), "tag": base64.b64encode(tag).decode(), }def decrypt(password: str, vault: dict) -> str: salt = base64.b64decode(vault["salt"]) nonce = base64.b64decode(vault["nonce"]) ciphertext = base64.b64decode(vault["ciphertext"]) tag = base64.b64decode(vault["tag"]) key = derive_key(password, salt) cipher = AES.new(key, AES.MODE_GCM, nonce=nonce) plaintext = cipher.decrypt_and_verify(ciphertext, tag) return plaintext.decode("utf-8")使用示例 # 加密 secret = '{"privateKey": "0xabcd..."}' vault = encrypt("my_strong_password", secret)# 存储为 JSON with open("vault.json", "w") as f: json.dump(vault, f, indent=2)# 解密 with open("vault.json") as f: vault = json.load(f)plaintext = decrypt("my_strong_password", vault) print(plaintext)vault.json 格式: { "salt": "base64...", "nonce": "base64...", "ciphertext": "base64...", "tag": "base64..." }为什么选 AES-GCM 而非 CBC模式 加密 完整性验证 推荐AES-CBC ✅ ❌(需额外 HMAC) 不推荐新项目AES-GCM ✅ ✅(内置 Tag) ✅ 推���AES-CTR ✅ ❌ 需配合 HMACGCM 模式同时提供加密和认证,decrypt_and_verify 会在解密前验证 Tag,密文被篡改时抛出 ValueError。 关键参数说明 PBKDF2 迭代次数:越高越安全,NIST 2023 建议 SHA-512 至少 210,000 次,MetaMask 等钱包用 600,000 次。代价是派生速度变慢(约 0.5~2 秒),对正常用户不感知,但让暴力破解成本提高数十万倍。 salt 唯一性:每次加密生成新的随机 salt,防止相同密码产生相同密钥(彩虹表攻击)。salt 不需要保密,公开存储即可。 nonce 唯一性:GCM 的 nonce 绝对不能重用于同一密钥,否则 GCM 的安全性完全崩溃。每次加密随机生成是最安全的做法。 密码错误时的行为 try: plaintext = decrypt("wrong_password", vault) except ValueError: print("密码错误或数据被篡改")decrypt_and_verify 验证 Tag 失败时抛出 ValueError,不会泄漏任何明文信息。

Permissions Policy Violation: unload is not allowed 是什么

Chrome 控制台偶尔出现: [Violation] Permissions policy violation: unload is not allowed in this document.不是代码报错,是一条警告。 原因 Chrome 正在逐步废弃 unload 事件,因为注册了 unload 的页面无法进入 BFCache(Back/Forward Cache),会降低导航性能。某些页面策略或 iframe 设置下,unload 会被直接禁止,此时任何注册 unload 的代码都会打印这条 Violation。 常见触发场景:第三方 SDK(Sentry、埋点、广告脚本)注册了 unload 旧版 Citrix/Enterprise 插件 页面在 <iframe> 里,父页面设置了 Permissions-Policy: unload=()是否影响功能 通常不影响。[Violation] 只是警告,页面照常运行,unload 回调不会执行而已。如果你的业务逻辑依赖 unload(如发送离开事件),需要改用 visibilitychange 或 pagehide。 查看当前页面的 Permissions Policy 方法一:Network 响应头 打开 DevTools → Network,刷新页面,点击 HTML 文档请求 → Response Headers,查找: Permissions-Policy: unload=()方法二:控制台查询 // 查看 unload 是否被策略禁止 document.permissionsPolicy?.allowsFeature("unload")// 查看所有允许的特性 document.permissionsPolicy.allowedFeatures()// 抓取当前页面响应头 fetch(location.href) .then(r => console.log(r.headers.get("Permissions-Policy")))定位是谁注册了 unload // 查看 window 上注册了哪些 unload 监听器 getEventListeners(window).unload// 查看 beforeunload getEventListeners(window).beforeunload如果有结果,点击 listener 里的函数名可以跳转到 Sources 对应代码。 也可以在 Sources 全局搜索: addEventListener("unload" window.onunload beforeunload推荐替代方案 // 替代 unload:页面对用户不可见时触发 document.addEventListener("visibilitychange", () => { if (document.visibilityState === "hidden") { // 发送最后的数据 navigator.sendBeacon("/api/leave", payload); } });// 替代 beforeunload(不阻塞 BFCache) window.addEventListener("pagehide", (e) => { if (e.persisted) { // 页面进入 BFCache,不是真正关闭 } });navigator.sendBeacon 在页面隐藏时异步发送请求,不阻塞页面关闭,是发送离开事件的首选方案。 Chrome Extension 的本地存储 Chrome 扩展用 chrome.storage.local 存储的数据保存在: Windows: %LOCALAPPDATA%\Google\Chrome\User Data\Default\Local Extension Settings\<扩展ID> macOS: ~/Library/Application Support/Google/Chrome/Default/Local Extension Settings/<扩展ID>目录内容是 LevelDB 格式(.log、.ldb 文件),不是纯文本。查看方法: # 在扩展页面控制台读取(需要 Inspect views 权限) chrome.storage.local.get(null, console.log)或用 Python plyvel 解析: import plyveldb = plyvel.DB("/path/to/extension/storage", create_if_missing=False) for k, v in db: print(k.decode(errors="replace")) print(v.decode(errors="replace")) db.close()注意:读取时浏览器需要关闭,否则 LevelDB 文件被锁。

格式化后文件仍存在:USB Mass Storage Gadget 只读模式排查

现象描述 USB Mass Storage Gadget 格式化完后:旧文件还在 可以创建新文件、写入数据 删除文件提示成功,重插后文件又出现原因分类 1. 存储设备进入只读模式 U 盘、TF 卡、eMMC 出现坏块时控制器会自动切换为 Read-Only。表现为删除"成功"但重新挂载后文件复原。 Linux 排查: dmesg | grep -i readonly dmesg | grep -i "write protect"出现以下字样即确认只读: Write Protect is on switching to read-only mode mmcblk0: read only2. Gadget 镜像文件损坏 如果通过镜像文件方式挂载(echo /data/usb.img > lun/file),镜像内 FAT/exFAT 文件系统可能损坏: # 检查镜像文件系统 fsck.vfat usb.img # 或 dosfsck usb.img3. Windows 快速格式化未重建文件系统 Windows "快速格式化"只重写 FAT 表,不实际清除旧数据,旧文件仍可被恢复工具读取。 彻底解决方式: 磁盘管理 → 删除分区 → 新建分区 → 完整格式化(取消勾选"快速格式化")4. OverlayFS 层隔离(Android Root 环境) TrickyStore、KernelSU、Magisk 等工具可能挂载了 OverlayFS,删除的是上层(upperdir),底层(lowerdir)文件仍然存在,重挂载后又出现。 mount | grep overlay如有输出,需要先卸载 overlay 再操作底层文件系统。 5. NAND Flash 已损坏 最符合"能写入但删除无效"的情形:控制器接收了写入缓存但没有真正落盘,重插后旧数据回来。 验证方式: touch test.txt && sync rm test.txt && sync umount /dev/sdX && mount /dev/sdX /mnt ls /mnt/test.txt # 如果文件还在,基本确认存储介质损坏修复方法 U 盘 / TF 卡(Linux) # 用 diskpart 或 dd 低格 sudo dd if=/dev/zero of=/dev/sdX bs=1M status=progressU 盘 / TF 卡(Windows) 以管理员运行 CMD: diskpart list disk select disk N clean create partition primary format fs=fat32 quick assign exitAndroid/Linux 开发板 eMMC eMMC 只读后一般无法软件修复,需要更换存储模块或使用厂商专用刷机工具重新初始化 flash 控制器。 快速定位表现象 最可能原因删除后重插文件回来 NAND 只读 / OverlayFS格式化后旧文件可见但访问慢 快速格式化(未清除)fsck 报错 镜像文件 FAT 损坏dmesg 有 write protect 存储介质已进入只读保护

Citrix Gateway 三种模式:Full VPN / Clientless / ICA Proxy 怎么区分

在公司里用 Citrix Gateway(以前叫 NetScaler Gateway)远程办公,能不能 ping 内网、能不能 mstsc 到某台内网机器——完全取决于管理员开的是哪种模式。三种模式差别很大: 三种模式 1. Full VPN(完整 VPN) 登录 Gateway 后建立 VPN 隧道,你的电脑相当于接进了公司内网。 能做的: ping 10.0.0.1 mstsc 10.0.0.100 \\10.0.0.50\share内网 API、SMB 共享、RDP 都能直接连。最接近传统 VPN。 2. Clientless VPN(无客户端 VPN) 只能通过 Gateway 的网页入口访问管理员发布过的内网网站: https://gateway.company.com/vpn/index.html ├─ OA 系统 ├─ JIRA ├─ GitLab └─ Exchange OWAGateway 帮你反向代理到内网。只有网页可访问——ping / RDP / SMB 全都不行。 3. ICA Proxy(最常见) 登录 Gateway 后看到的不是网页应用列表,而是远程桌面 / 应用: [Windows 桌面] [SAP] [Outlook] [Chrome]点击后:浏览器下载 .ica 文件 Citrix Workspace 客户端打开 连到内网一台服务器上运行你本机没进内网——只是远程操作一台内网机器。所有操作都在那台远端上完成,本机能看到的只是画面像素。 怎么判断自己是哪种 登录 Gateway 之后: 方法 1:看网卡 ipconfigFull VPN 会多出: 以太网适配器 Citrix Secure Access: 以太网适配器 Citrix VPN Adapter:看到就是 Full VPN。 方法 2:看路由 route printFull VPN 里有内网网段被路由到 Citrix 虚拟网卡: 10.0.0.0 255.0.0.0 10.0.0.1 <Citrix 网卡 IP>方法 3:直接 ping 内网 ping 10.x.x.x telnet 10.x.x.x 3389通 = Full VPN,不通 = Clientless 或 ICA Proxy。 方法 4:登录后看到什么 登录 Gateway 网页后:看到 大概率是一堆网页链接 Clientless VPN桌面 / 应用图标(点了下 ica) ICA Proxy什么都没看到,只有 VPN 状态 Full VPNICA Proxy 想访问其它内网资源 基本上不行。ICA Proxy 的设计初衷就是"给远程用户桌面 / 应用",不给完整内网访问权限。安全模型里这是"最小暴露面"的选择。 想访问需要管理员:开启 Full VPN 策略(Citrix Secure Access Client) 或者把你需要的服务发布成 Clientless 应用 或者给你专门开一个 RDP 会话,你从那台机器上操作传大文件的坑 ICA Proxy 模式下想把本机文件传到远端会话:Citrix Workspace 支持"客户端驱动映射",可以把本地磁盘挂进远端会话,管理员可能禁用 剪贴板:可能双向、可能单向、可能禁用,也是策略控制的 上传下载按钮:Citrix Workspace 本身有,但公司常常禁真被卡住只能靠在远端邮箱收发、通过 WebOA 上传中转等等。或者直接找 IT 开权限。 Full VPN 的坑 即使有 Full VPN 也不等于什么都能访问:分段路由:管理员可能只给部分内网网段路由,比如只给你 10.10.0.0/16,其它照样不通 应用层过滤:Gateway 可以按端口 / 协议限制,明明有路由但 RDP 不通 DNS:需要用公司内 DNS,否则内网域名解析不了route print 看到给了哪些网段,就只能访问那些网段。 一句话总结 Citrix Gateway 三种模式—— Full VPN 拿到内网路由、Clientless 只发布网页、ICA Proxy 只是远端桌面像素。看 ipconfig 有没有 Citrix 网卡最快分辨。想要更多权限,只能找管理员改策略。