iT邦幫忙

2025 iThome 鐵人賽

DAY 23
0
Security

醫療數據的資安挑戰與創新解決方案系列 第 25

病人端加密上傳與伺服器儲存 — 醫療數據安全流程完整化

  • 分享至 

  • xImage
  •  

今天的目標是讓病人端能安全地將醫療資料加密後再傳送到伺服器,並由伺服器驗證使用者身分(Token)後,將資料安全儲存到資料庫中。這樣能避免病歷在傳輸過程或資料庫中遭到竊取或外洩,並且與昨天的「醫師查詢」串接,形成完整的資安流程:
病人上傳 → 伺服器驗證與存放 → 醫師查詢解密

一、理論重點

  1. 病人端資料加密:病人資料(血壓、心跳、備註)必須在送出前用金鑰加密,避免在傳輸途中遭竊聽。

  2. 伺服器驗證與授權:伺服器需確認請求來源是否為病人角色(Token 驗證),拒絕未授權的上傳。

  3. 資料庫安全存放:病歷不以明文存放,而是以加密後的資料寫入 MySQL,避免駭客入侵資料庫後直接竊取敏感資訊。

  4. 完整流程串接:結合醫師查詢解密功能,達成安全的「上傳 + 查詢」閉環。

二、案例分享

2015 年美國 Anthem 醫療保險公司遭駭客入侵,近 8000 萬筆病患與員工個資外洩,包含姓名、生日、醫療紀錄與社會安全號碼。調查發現,部分原因是資料庫沒有做加密保護,導致駭客一旦取得存取權限,就能直接讀取所有明文紀錄。這事件提醒我們,醫療資料在儲存時必須加密,並搭配存取控制與權限驗證,才能降低被駭後的風險。

三、簡單程式範例

server.py

# server.py
from fastapi import FastAPI, Request, HTTPException
import mysql.connector
from cryptography.fernet import Fernet
import json
import base64
from datetime import datetime

app = FastAPI()

# 模擬 Token
TOKENS = {
    "patient123": "patient",
    "doctor123": "doctor"
}

# 使用固定金鑰(避免每次重啟不同)
KEY = Fernet.generate_key()
cipher = Fernet(KEY)
print("Encryption Key (記得保存以便解密):", KEY.decode())

# 建立 MySQL 連線
def get_db():
    return mysql.connector.connect(
        host="localhost",
        user="root",
        password="Joy940819",  # 改成你的 MySQL root 密碼
        database="health"
    )

# 病人上傳數據
@app.post("/upload")
async def upload(request: Request):
    token = request.headers.get("Authorization")
    if TOKENS.get(token) != "patient":
        raise HTTPException(status_code=401, detail="Unauthorized")

    data = await request.json()
    device_id = data.get("device_id")
    systolic = data.get("systolic")
    diastolic = data.get("diastolic")
    pulse = data.get("pulse")
    note = data.get("note", "")

    # 把資料加密後存 MySQL
    enc_note = cipher.encrypt(note.encode())

    conn = get_db()
    cur = conn.cursor()
    cur.execute("""
        INSERT INTO blood_pressure (device_id, systolic, diastolic, pulse, created_at)
        VALUES (%s, %s, %s, %s, NOW())
    """, (device_id, systolic, diastolic, pulse))
    conn.commit()
    cur.close()
    conn.close()

    return {"status": "ok", "record": data}

# 醫師查詢最新 5 筆數據
@app.get("/records")
async def records(request: Request):
    token = request.headers.get("Authorization")
    if TOKENS.get(token) != "doctor":
        raise HTTPException(status_code=401, detail="Unauthorized")

    conn = get_db()
    cur = conn.cursor(dictionary=True)
    cur.execute("SELECT * FROM blood_pressure ORDER BY created_at DESC LIMIT 5")
    rows = cur.fetchall()
    cur.close()
    conn.close()

    return {"records": rows}

device.py

# device.py
import requests
from cryptography.fernet import Fernet

# 對應 server.py 的 key
KEY = b"Xe_T53LwKd3nPAqNLC_EqHYkwZqKi2dnfepvTArGRFQ="  #從server.py中得到的密碼
cipher = Fernet(KEY)

url = "http://127.0.0.1:8000/upload"
headers = {"Authorization": "patient123"}

payload = {
    "device_id": "device-001",
    "systolic": 120,
    "diastolic": 80,
    "pulse": 75,
    "note": "測試傳輸"
}

res = requests.post(url, json=payload, headers=headers)

print("Status:", res.status_code)
try:
    print("Response:", res.json())
except:
    print("非 JSON 回應:", res.text)

server.py 是後端 API 伺服器,用來接收病人裝置傳送的血壓資料並存進 MySQL,醫師端可以透過授權查詢最新的病歷紀錄;而 device.py 則是模擬 IoT 血壓計,將測到的數據上傳到伺服器,兩者一起構成一個簡單的醫療 IoT 平台流程。執行的結果如下

https://ithelp.ithome.com.tw/upload/images/20251001/20169331fLC5SYaJW9.png


上一篇
勒索病毒對醫療機構的威脅
下一篇
醫療數據上鏈與雲端整合流程設計
系列文
醫療數據的資安挑戰與創新解決方案29
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言