設計思路-數據庫字段加密

說明

線上運行很久的項目,用戶反饋用戶手機號需要數據層面做加密,用戶場景用戶相關字段十分銘感

我們以前就出現過數據庫用戶訂單信息泄露 手機號是明文 然後騙子打電話把客戶騙了

 

現狀

代碼裏面大量,的sql拼接,或者上層透傳拼接sql,導致不確定要改的地方有多少,而且迴歸測試的地方又很多,或者下次用戶又要郵件加密呢。代價成本大

而且我們是hibernate和mybatis混用

還涉及到hibernate的級聯查詢,如果級聯返回用戶信息手機是密文出問題

 

方案

1.通過JsqlParse解析sql樹,在DataSource層面做替換  比如select * from user where mobile={mobile}  mobile參數替換成密文傳到數據庫,  查詢結果返回字段在應用層面也對應解密

2.有些特殊情況要在數據庫做解密函數做處理

替換前

select * from ticke where phone in(select phone  from user where id=1)

select * from user where phone like '%1312827%'

替換後

select * from ticke where phone in(select aes_decrypt(phone,'salt')  from user where id=1)

select * from user where aes_decrypt(phone,'salt') like '%1312827%'

面臨問題

各種複雜的sql動態拼接,或者有些沒考慮到的複雜sql萬一沒改到怎麼辦 這樣全局處理不是有風險

SELECT *
FROM user u
WHERE u.provider_id = ?
    AND u.valid = true
    AND u.deleted = false
    AND u.type = ?
    AND (u.suspended = ?
        OR u.suspended IS NULL)
    AND (CONCAT_WS(?, u.`name`, u.nickname, u.email, u.phone, u.mobile_phone, u.notes, u.signature) LIKE ?
        OR u.id IN (
            SELECT urt.user_id
            FROM user_r_tag urt
                LEFT JOIN tag t ON t.id = urt.tag_id
            WHERE t.provider_id = ?
                AND t.`name` LIKE ?
        ))
ORDER BY u.created_at DESC
LIMIT ?, ?

解決方式

其實換一種思路就可以解決,在dataSource 加個採集所有的程序運行sql,然後根據寫好的腳本程序解析替換所有sql跑一遍 驗證,不符合預期的再針對性改

這樣風險就小很多了

以下是我採集的sql

 

 

jqlparse使用

邏輯和考慮場景應該挺複雜的 可以參考開源的一些框架 比如mybatis 支持脫敏 還有sharding的一鍵脫敏

1.引入pom依賴

        <dependency>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
            <version>4.3</version>
        </dependency>

2.例子

    public static void main(String[] args) throws JSQLParserException {
             String sql="\n" +
                     "SELECT sd.name AS \"serviceDesk_name\", t.no AS \"no\", wt.name AS \"workflowTemplate_name\", ru.name AS \"requester_name\", t.subject AS \"subject\"\n" +
                     "\t, eg.nickname AS \"engineer_nickname\", create_user.name AS \"user_name\", t.priority AS \"priority\", via.channel_name AS \"via_channel_name\", eu.name AS \"engineer_user_name\"\n" +
                     "\t, t.created_at AS \"created_at\", t.deleted AS \"deleted\", create_user.email AS \"user_email\", ru.mobile_phone AS \"requester_mobilePhone\", t.id AS \"id\"\n" +
                     "\t, t.status AS \"status\", ru.email AS \"requester_email\", t.updated_at AS \"updated_at\", t.engineer_id AS \"engineer_id\", eu.id AS \"engineer_user_id\"\n" +
                     "\t, t.requester_id AS \"requester_id\", ug.id AS \"requester_userGroup_id\", t.service_desk_id AS \"serviceDesk_id\", t.via_id AS \"via_id\", t.user_id AS \"user_id\"\n" +
                     "\t, t.workflow_template_id AS \"workflowTemplate_id\"\n" +
                     "FROM ticket t\n" +
                     "\tLEFT JOIN engineer eg ON t.engineer_id = eg.id\n" +
                     "\tLEFT JOIN `user` eu ON eg.user_id = eu.id\n" +
                     "\tINNER JOIN `user` ru ON t.requester_id = ru.id\n" +
                     "\tLEFT JOIN user_group ug ON ru.user_group_id = ug.id\n" +
                     "\tLEFT JOIN service_desk sd ON sd.id = t.service_desk_id\n" +
                     "\tLEFT JOIN via via ON via.id = t.via_id\n" +
                     "\tLEFT JOIN user create_user ON t.user_id = create_user.id\n" +
                     "\tLEFT JOIN workflow_template wt ON t.workflow_template_id = wt.id\n" +
                     "WHERE t.provider_id = ?\n" +
                     "\tAND t.status = ?\n" +
                     "\tAND t.engineer_id IS NULL\n" +
                     "\tAND (t.deleted = false\n" +
                     "\t\tOR t.deleted IS NULL)\n" +
                     "\tAND (t.service_desk_id IN (\n" +
                     "\t\t\tSELECT DISTINCT temp.service_desk_id\n" +
                     "\t\t\tFROM (\n" +
                     "\t\t\t\tSELECT ersd.service_desk_id\n" +
                     "\t\t\t\tFROM engineer_r_service_desk ersd\n" +
                     "\t\t\t\tWHERE ersd.engineer_id = ?\n" +
                     "\t\t\t\tUNION\n" +
                     "\t\t\t\tSELECT jsd.joint_service_desk_id\n" +
                     "\t\t\t\tFROM joint_service_desk jsd\n" +
                     "\t\t\t\tWHERE jsd.service_desk_id IN (\n" +
                     "\t\t\t\t\tSELECT ersd2.service_desk_id\n" +
                     "\t\t\t\t\tFROM engineer_r_service_desk ersd2\n" +
                     "\t\t\t\t\tWHERE ersd2.engineer_id = ?\n" +
                     "\t\t\t\t)\n" +
                     "\t\t\t) temp\n" +
                     "\t\t)\n" +
                     "\t\tOR t.engineer_id = ?\n" +
                     "\t\tOR t.user_id = (\n" +
                     "\t\t\tSELECT e.user_id\n" +
                     "\t\t\tFROM engineer e\n" +
                     "\t\t\tWHERE e.id = ?\n" +
                     "\t\t)\n" +
                     "\t\tOR t.id IN (\n" +
                     "\t\t\tSELECT trc.ticket_id\n" +
                     "\t\t\tFROM ticket_r_cc trc\n" +
                     "\t\t\tWHERE trc.user_id = (\n" +
                     "\t\t\t\t\tSELECT e.user_id\n" +
                     "\t\t\t\t\tFROM engineer e\n" +
                     "\t\t\t\t\tWHERE e.id = ?\n" +
                     "\t\t\t\t)\n" +
                     "\t\t\t\tOR trc.service_desk_id = (\n" +
                     "\t\t\t\t\tSELECT e.default_service_desk_id\n" +
                     "\t\t\t\t\tFROM engineer e\n" +
                     "\t\t\t\t\tWHERE e.id = ?\n" +
                     "\t\t\t\t)\n" +
                     "\t\t)\n" +
                     "\t\tOR t.requester_id = (\n" +
                     "\t\t\tSELECT e.user_id\n" +
                     "\t\t\tFROM engineer e\n" +
                     "\t\t\tWHERE e.id = ?\n" +
                     "\t\t))\n" +
                     "ORDER BY t.id DESC";

        Statement statement = pm.parse(new StringReader(sql));
        int i=0;
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章