返回列表 上一筆 下一筆

📄 資料內容

# Spring Boot + Jasypt 最終整合:

## `ENC(...)` 用 legacy(MD5+DES),協力廠商通訊用 `encryptorBean`



> 目標:

> - `application.yml` 的 `ENC(...)` 由 **legacy**(`PBEWithMD5AndDES` + `NoIv` + `vu4wj/3`)自動解密。

> - 協力廠商提供的 **`@Bean("encryptorBean")`** 僅供**程式碼**手動加解密通訊資料,不參與組態自動解密。



---



## 1) application.yml(只放參數,不指定 bean 名)

```yaml

jasypt:

  encryptor:

    algorithm: PBEWithMD5AndDES

    iv-generator-classname: org.jasypt.iv.NoIvGenerator

    password: vu4wj/3

# 不要設定 jasypt.encryptor.bean

```

說明:`ulisesbocchio/jasypt-spring-boot` 會依上述參數自動解 `ENC(...)`,無需指定 Bean 名。



---



## 2) 啟用註解設定(避免指定 encryptorBean)

若專案有使用 `@EnableEncryptableProperties`(或你說的 `@enableEncrypt`),**不要**指向協力廠商的 Bean 名。

```java

// 正確:讓 starter 依 application.yml 的參數處理

@EnableEncryptableProperties



// 錯誤示例(會把組態解密交給協力廠商 encryptorBean,造成衝突):

// @EnableEncryptableProperties(encryptorBean = "encryptorBean")

```



---



## 3) 協力廠商提供的 Encryptor(顯式 Bean 名,只給程式碼用)

```java

@Configuration

public class PartnerCryptoConfig {



    @Bean("encryptorBean") // 協力廠商指定的 Bean 名

    public StringEncryptor vendorEncryptor() {

        String p1 = System.getProperty("P_ENV_1");

        String p2 = System.getProperty("P_ENV_2");

        if (p1 == null || p1.isBlank() || "null".equalsIgnoreCase(p1)

         || p2 == null || p2.isBlank() || "null".equalsIgnoreCase(p2)) {

            p1 = System.getenv("P_ENV_1");

            p2 = System.getenv("P_ENV_2");

        }

        String salt = (p1 == null ? "" : p1) + (p2 == null ? "" : p2);



        PooledPBEStringEncryptor enc = new PooledPBEStringEncryptor();

        SimpleStringPBEConfig cfg = new SimpleStringPBEConfig();

        cfg.setPassword(salt);

        cfg.setAlgorithm("PBEWithHmacSHA512AndAES_256");

        cfg.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");

        cfg.setKeyObtentionIterations("1000");

        cfg.setPoolSize("1");

        cfg.setProviderName("SunJCE");

        cfg.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");

        cfg.setStringOutputType("base64");

        enc.setConfig(cfg);

        return enc;

    }

}

```

**使用方式(務必加 `@Qualifier`)**:

```java

@Service

public class PartnerCommService {

    private final StringEncryptor partner;



    public PartnerCommService(@Qualifier("encryptorBean") StringEncryptor partner) {

        this.partner = partner;

    }



    public String encryptForPartner(String plain) { return partner.encrypt(plain); }

    public String decryptFromPartner(String cipher) { return partner.decrypt(cipher); }

}

```



---



## 4) 常見衝突與排除

- **衝突 1:組態解密被導向 `encryptorBean`**

  檢查是否在註解或屬性把 `encryptorBean` 指定為解組態用(例如 `@EnableEncryptableProperties(encryptorBean = "encryptorBean")` 或 `jasypt.encryptor.bean=encryptorBean`)。**移除這些指定**。

- **衝突 2:注入歧義(found 2 beans of type StringEncryptor)**

  避免裸 `@Autowired StringEncryptor`。凡要用協力廠商版本,一律 `@Qualifier("encryptorBean")`;需要的話也可把對外服務包成自己的 Service,別直接注入 `StringEncryptor`。



---



## 5) 可選:若也想在程式碼中取得 legacy Encryptor

一般不需要(starter 會內部用 legacy 參數解組態)。若確實需要,可加:

```java

@Configuration

class LegacyExposureConfig {

    @Bean("legacyEncryptor")

    public StringEncryptor legacyBean(@Value("${jasypt.encryptor.password}") String pw) {

        PooledPBEStringEncryptor enc = new PooledPBEStringEncryptor();

        SimpleStringPBEConfig cfg = new SimpleStringPBEConfig();

        cfg.setPassword(pw);

        cfg.setAlgorithm("PBEWithMD5AndDES");

        cfg.setIvGeneratorClassName("org.jasypt.iv.NoIvGenerator");

        cfg.setPoolSize("1");

        cfg.setStringOutputType("base64");

        enc.setConfig(cfg);

        return enc;

    }

}

```

前提:所有注入點都用 `@Qualifier("legacyEncryptor")`,避免與 `encryptorBean` 產生歧義。



---



## 6) 驗證清單

- 啟動時 **不要**有 `expected single matching bean but found 2` 的錯誤。

- `application.yml` 內 `ENC(...)` 能順利還原(印出資料源連線、或以測試程式驗證)。

- 協力廠商的收送資料可用 `@Qualifier("encryptorBean")` 成功加解密。

- `@EnableEncryptableProperties` 沒有把 `encryptorBean` 指定為解組態用。



---



## 7) 安全與後續

- legacy(MD5+DES + NoIv)僅做相容使用;對外通訊與新資料請一律走協力廠商 AES-256 版本。

- 若未來要把組態也升級為 AES-256,可逐步把密文轉換,再改用路由/新 Bean 名處理。

🔐 Base64 編碼內容

IyBTcHJpbmcgQm9vdCArIEphc3lwdCDmnIDntYLmlbTlkIjvvJoKCiMjIGBFTkMoLi4uKWAg55SoIGxlZ2Fjee+8iE1ENStERVPvvInvvIzljZTlipvlu6DllYbpgJroqIrnlKggYGVuY3J5cHRvckJlYW5gCgoKCj4g55uu5qiZ77yaCgo+IC0gYGFwcGxpY2F0aW9uLnltbGAg55qEIGBFTkMoLi4uKWAg55SxICoqbGVnYWN5KirvvIhgUEJFV2l0aE1ENUFuZERFU2AgKyBgTm9JdmAgKyBgdnU0d2ovM2DvvInoh6rli5Xop6Plr4bjgIIKCj4gLSDljZTlipvlu6DllYbmj5DkvpvnmoQgKipgQEJlYW4oImVuY3J5cHRvckJlYW4iKWAqKiDlg4XkvpsqKueoi+W8j+eivCoq5omL5YuV5Yqg6Kej5a+G6YCa6KiK6LOH5paZ77yM5LiN5Y+D6IiH57WE5oWL6Ieq5YuV6Kej5a+G44CCCgoKCi0tLQoKCgojIyAxKSBhcHBsaWNhdGlvbi55bWzvvIjlj6rmlL7lj4PmlbjvvIzkuI3mjIflrpogYmVhbiDlkI3vvIkKCmBgYHlhbWwKCmphc3lwdDoKCiAgZW5jcnlwdG9yOgoKICAgIGFsZ29yaXRobTogUEJFV2l0aE1ENUFuZERFUwoKICAgIGl2LWdlbmVyYXRvci1jbGFzc25hbWU6IG9yZy5qYXN5cHQuaXYuTm9JdkdlbmVyYXRvcgoKICAgIHBhc3N3b3JkOiB2dTR3ai8zCgojIOS4jeimgeioreWumiBqYXN5cHQuZW5jcnlwdG9yLmJlYW4KCmBgYAoK6Kqq5piO77yaYHVsaXNlc2JvY2NoaW8vamFzeXB0LXNwcmluZy1ib290YCDmnIPkvp3kuIrov7Dlj4Pmlbjoh6rli5Xop6MgYEVOQyguLi4pYO+8jOeEoemcgOaMh+WumiBCZWFuIOWQjeOAggoKCgotLS0KCgoKIyMgMikg5ZWf55So6Ki76Kej6Kit5a6a77yI6YG/5YWN5oyH5a6aIGVuY3J5cHRvckJlYW7vvIkKCuiLpeWwiOahiOacieS9v+eUqCBgQEVuYWJsZUVuY3J5cHRhYmxlUHJvcGVydGllc2DvvIjmiJbkvaDoqqrnmoQgYEBlbmFibGVFbmNyeXB0YO+8ie+8jCoq5LiN6KaBKirmjIflkJHljZTlipvlu6DllYbnmoQgQmVhbiDlkI3jgIIKCmBgYGphdmEKCi8vIOato+eiuu+8muiukyBzdGFydGVyIOS+nSBhcHBsaWNhdGlvbi55bWwg55qE5Y+D5pW46JmV55CGCgpARW5hYmxlRW5jcnlwdGFibGVQcm9wZXJ0aWVzCgoKCi8vIOmMr+iqpOekuuS+i++8iOacg+aKiue1hOaFi+ino+WvhuS6pOe1puWNlOWKm+W7oOWVhiBlbmNyeXB0b3JCZWFu77yM6YCg5oiQ6KGd56qB77yJ77yaCgovLyBARW5hYmxlRW5jcnlwdGFibGVQcm9wZXJ0aWVzKGVuY3J5cHRvckJlYW4gPSAiZW5jcnlwdG9yQmVhbiIpCgpgYGAKCgoKLS0tCgoKCiMjIDMpIOWNlOWKm+W7oOWVhuaPkOS+m+eahCBFbmNyeXB0b3LvvIjpoa/lvI8gQmVhbiDlkI3vvIzlj6rntabnqIvlvI/norznlKjvvIkKCmBgYGphdmEKCkBDb25maWd1cmF0aW9uCgpwdWJsaWMgY2xhc3MgUGFydG5lckNyeXB0b0NvbmZpZyB7CgoKCiAgICBAQmVhbigiZW5jcnlwdG9yQmVhbiIpIC8vIOWNlOWKm+W7oOWVhuaMh+WumueahCBCZWFuIOWQjQoKICAgIHB1YmxpYyBTdHJpbmdFbmNyeXB0b3IgdmVuZG9yRW5jcnlwdG9yKCkgewoKICAgICAgICBTdHJpbmcgcDEgPSBTeXN0ZW0uZ2V0UHJvcGVydHkoIlBfRU5WXzEiKTsKCiAgICAgICAgU3RyaW5nIHAyID0gU3lzdGVtLmdldFByb3BlcnR5KCJQX0VOVl8yIik7CgogICAgICAgIGlmIChwMSA9PSBudWxsIHx8IHAxLmlzQmxhbmsoKSB8fCAibnVsbCIuZXF1YWxzSWdub3JlQ2FzZShwMSkKCiAgICAgICAgIHx8IHAyID09IG51bGwgfHwgcDIuaXNCbGFuaygpIHx8ICJudWxsIi5lcXVhbHNJZ25vcmVDYXNlKHAyKSkgewoKICAgICAgICAgICAgcDEgPSBTeXN0ZW0uZ2V0ZW52KCJQX0VOVl8xIik7CgogICAgICAgICAgICBwMiA9IFN5c3RlbS5nZXRlbnYoIlBfRU5WXzIiKTsKCiAgICAgICAgfQoKICAgICAgICBTdHJpbmcgc2FsdCA9IChwMSA9PSBudWxsID8gIiIgOiBwMSkgKyAocDIgPT0gbnVsbCA/ICIiIDogcDIpOwoKCgogICAgICAgIFBvb2xlZFBCRVN0cmluZ0VuY3J5cHRvciBlbmMgPSBuZXcgUG9vbGVkUEJFU3RyaW5nRW5jcnlwdG9yKCk7CgogICAgICAgIFNpbXBsZVN0cmluZ1BCRUNvbmZpZyBjZmcgPSBuZXcgU2ltcGxlU3RyaW5nUEJFQ29uZmlnKCk7CgogICAgICAgIGNmZy5zZXRQYXNzd29yZChzYWx0KTsKCiAgICAgICAgY2ZnLnNldEFsZ29yaXRobSgiUEJFV2l0aEhtYWNTSEE1MTJBbmRBRVNfMjU2Iik7CgogICAgICAgIGNmZy5zZXRJdkdlbmVyYXRvckNsYXNzTmFtZSgib3JnLmphc3lwdC5pdi5SYW5kb21JdkdlbmVyYXRvciIpOwoKICAgICAgICBjZmcuc2V0S2V5T2J0ZW50aW9uSXRlcmF0aW9ucygiMTAwMCIpOwoKICAgICAgICBjZmcuc2V0UG9vbFNpemUoIjEiKTsKCiAgICAgICAgY2ZnLnNldFByb3ZpZGVyTmFtZSgiU3VuSkNFIik7CgogICAgICAgIGNmZy5zZXRTYWx0R2VuZXJhdG9yQ2xhc3NOYW1lKCJvcmcuamFzeXB0LnNhbHQuUmFuZG9tU2FsdEdlbmVyYXRvciIpOwoKICAgICAgICBjZmcuc2V0U3RyaW5nT3V0cHV0VHlwZSgiYmFzZTY0Iik7CgogICAgICAgIGVuYy5zZXRDb25maWcoY2ZnKTsKCiAgICAgICAgcmV0dXJuIGVuYzsKCiAgICB9Cgp9CgpgYGAKCioq5L2/55So5pa55byP77yI5YuZ5b+F5YqgIGBAUXVhbGlmaWVyYO+8iSoq77yaCgpgYGBqYXZhCgpAU2VydmljZQoKcHVibGljIGNsYXNzIFBhcnRuZXJDb21tU2VydmljZSB7CgogICAgcHJpdmF0ZSBmaW5hbCBTdHJpbmdFbmNyeXB0b3IgcGFydG5lcjsKCgoKICAgIHB1YmxpYyBQYXJ0bmVyQ29tbVNlcnZpY2UoQFF1YWxpZmllcigiZW5jcnlwdG9yQmVhbiIpIFN0cmluZ0VuY3J5cHRvciBwYXJ0bmVyKSB7CgogICAgICAgIHRoaXMucGFydG5lciA9IHBhcnRuZXI7CgogICAgfQoKCgogICAgcHVibGljIFN0cmluZyBlbmNyeXB0Rm9yUGFydG5lcihTdHJpbmcgcGxhaW4pIHsgcmV0dXJuIHBhcnRuZXIuZW5jcnlwdChwbGFpbik7IH0KCiAgICBwdWJsaWMgU3RyaW5nIGRlY3J5cHRGcm9tUGFydG5lcihTdHJpbmcgY2lwaGVyKSB7IHJldHVybiBwYXJ0bmVyLmRlY3J5cHQoY2lwaGVyKTsgfQoKfQoKYGBgCgoKCi0tLQoKCgojIyA0KSDluLjopovooZ3nqoHoiIfmjpLpmaQKCi0gKirooZ3nqoEgMe+8mue1hOaFi+ino+Wvhuiiq+WwjuWQkSBgZW5jcnlwdG9yQmVhbmAqKiAgCgogIOaqouafpeaYr+WQpuWcqOiou+ino+aIluWxrOaAp+aKiiBgZW5jcnlwdG9yQmVhbmAg5oyH5a6a54K66Kej57WE5oWL55So77yI5L6L5aaCIGBARW5hYmxlRW5jcnlwdGFibGVQcm9wZXJ0aWVzKGVuY3J5cHRvckJlYW4gPSAiZW5jcnlwdG9yQmVhbiIpYCDmiJYgYGphc3lwdC5lbmNyeXB0b3IuYmVhbj1lbmNyeXB0b3JCZWFuYO+8ieOAgioq56e76Zmk6YCZ5Lqb5oyH5a6aKirjgIIKCi0gKirooZ3nqoEgMu+8muazqOWFpeatp+e+qe+8iGZvdW5kIDIgYmVhbnMgb2YgdHlwZSBTdHJpbmdFbmNyeXB0b3LvvIkqKiAgCgogIOmBv+WFjeijuCBgQEF1dG93aXJlZCBTdHJpbmdFbmNyeXB0b3Jg44CC5Yeh6KaB55So5Y2U5Yqb5bug5ZWG54mI5pys77yM5LiA5b6LIGBAUXVhbGlmaWVyKCJlbmNyeXB0b3JCZWFuIilg77yb6ZyA6KaB55qE6Kmx5Lmf5Y+v5oqK5bCN5aSW5pyN5YuZ5YyF5oiQ6Ieq5bex55qEIFNlcnZpY2XvvIzliKXnm7TmjqXms6jlhaUgYFN0cmluZ0VuY3J5cHRvcmDjgIIKCgoKLS0tCgoKCiMjIDUpIOWPr+mBuO+8muiLpeS5n+aDs+WcqOeoi+W8j+eivOS4reWPluW+lyBsZWdhY3kgRW5jcnlwdG9yCgrkuIDoiKzkuI3pnIDopoHvvIhzdGFydGVyIOacg+WFp+mDqOeUqCBsZWdhY3kg5Y+D5pW46Kej57WE5oWL77yJ44CC6Iul56K65a+m6ZyA6KaB77yM5Y+v5Yqg77yaCgpgYGBqYXZhCgpAQ29uZmlndXJhdGlvbgoKY2xhc3MgTGVnYWN5RXhwb3N1cmVDb25maWcgewoKICAgIEBCZWFuKCJsZWdhY3lFbmNyeXB0b3IiKQoKICAgIHB1YmxpYyBTdHJpbmdFbmNyeXB0b3IgbGVnYWN5QmVhbihAVmFsdWUoIiR7amFzeXB0LmVuY3J5cHRvci5wYXNzd29yZH0iKSBTdHJpbmcgcHcpIHsKCiAgICAgICAgUG9vbGVkUEJFU3RyaW5nRW5jcnlwdG9yIGVuYyA9IG5ldyBQb29sZWRQQkVTdHJpbmdFbmNyeXB0b3IoKTsKCiAgICAgICAgU2ltcGxlU3RyaW5nUEJFQ29uZmlnIGNmZyA9IG5ldyBTaW1wbGVTdHJpbmdQQkVDb25maWcoKTsKCiAgICAgICAgY2ZnLnNldFBhc3N3b3JkKHB3KTsKCiAgICAgICAgY2ZnLnNldEFsZ29yaXRobSgiUEJFV2l0aE1ENUFuZERFUyIpOwoKICAgICAgICBjZmcuc2V0SXZHZW5lcmF0b3JDbGFzc05hbWUoIm9yZy5qYXN5cHQuaXYuTm9JdkdlbmVyYXRvciIpOwoKICAgICAgICBjZmcuc2V0UG9vbFNpemUoIjEiKTsKCiAgICAgICAgY2ZnLnNldFN0cmluZ091dHB1dFR5cGUoImJhc2U2NCIpOwoKICAgICAgICBlbmMuc2V0Q29uZmlnKGNmZyk7CgogICAgICAgIHJldHVybiBlbmM7CgogICAgfQoKfQoKYGBgCgrliY3mj5DvvJrmiYDmnInms6jlhaXpu57pg73nlKggYEBRdWFsaWZpZXIoImxlZ2FjeUVuY3J5cHRvciIpYO+8jOmBv+WFjeiIhyBgZW5jcnlwdG9yQmVhbmAg55Si55Sf5q2n576p44CCCgoKCi0tLQoKCgojIyA2KSDpqZforYnmuIXllq4KCi0g5ZWf5YuV5pmCICoq5LiN6KaBKirmnIkgYGV4cGVjdGVkIHNpbmdsZSBtYXRjaGluZyBiZWFuIGJ1dCBmb3VuZCAyYCDnmoTpjK/oqqTjgIIKCi0gYGFwcGxpY2F0aW9uLnltbGAg5YWnIGBFTkMoLi4uKWAg6IO96aCG5Yip6YKE5Y6f77yI5Y2w5Ye66LOH5paZ5rqQ6YCj57ea44CB5oiW5Lul5ris6Kmm56iL5byP6amX6K2J77yJ44CCCgotIOWNlOWKm+W7oOWVhueahOaUtumAgeizh+aWmeWPr+eUqCBgQFF1YWxpZmllcigiZW5jcnlwdG9yQmVhbiIpYCDmiJDlip/liqDop6Plr4bjgIIKCi0gYEBFbmFibGVFbmNyeXB0YWJsZVByb3BlcnRpZXNgIOaykuacieaKiiBgZW5jcnlwdG9yQmVhbmAg5oyH5a6a54K66Kej57WE5oWL55So44CCCgoKCi0tLQoKCgojIyA3KSDlronlhajoiIflvoznuowKCi0gbGVnYWN577yITUQ1K0RFUyArIE5vSXbvvInlg4XlgZrnm7jlrrnkvb/nlKjvvJvlsI3lpJbpgJroqIroiIfmlrDos4fmlpnoq4vkuIDlvovotbDljZTlipvlu6DllYYgQUVTLTI1NiDniYjmnKzjgIIKCi0g6Iul5pyq5L6G6KaB5oqK57WE5oWL5Lmf5Y2H57Sa54K6IEFFUy0yNTbvvIzlj6/pgJDmraXmiorlr4bmlofovYnmj5vvvIzlho3mlLnnlKjot6/nlLEv5pawIEJlYW4g5ZCN6JmV55CG44CCCg==
返回列表 上一筆 下一筆