如何有效預(yù)防脫庫
本篇不從DBA、網(wǎng)絡(luò)架構(gòu)層面來講述數(shù)據(jù)安全,這部分有很專業(yè)的架構(gòu)和云上產(chǎn)品來解決,本篇重點(diǎn)從開發(fā)人員角度講述如何避免數(shù)據(jù)安全的漏洞。
相信大部分人都看到過這樣的新聞,某某論壇泄漏了用戶密碼,某某物流公司泄漏了用戶的手機(jī)號等等,我一直堅(jiān)信大部分?jǐn)?shù)據(jù)泄漏都是內(nèi)部管理出現(xiàn)了問題,大部分都是內(nèi)部團(tuán)隊(duì)有意或無意泄漏了數(shù)據(jù),如果要從外界通過漏洞攻克不是沒有可能但是成本是巨大的,所以人為的泄漏往往是需要更加關(guān)注的問題,那作為軟件生產(chǎn)的主力軍(程序員)如何來避免挖坑?那我們接下來就主要講講從開發(fā)角度如何避免數(shù)據(jù)泄漏的可能性。
從網(wǎng)上找了一些?數(shù)據(jù)安全治理?的相關(guān)資料,有興趣可以參考一下。
我們從程序員角度來講講如何有效的預(yù)防數(shù)據(jù)安全問題。
數(shù)據(jù)的訪問控制
我們先來看看哪些是經(jīng)常訪問數(shù)據(jù)庫的用戶?
軟件程序(應(yīng)用程序、數(shù)據(jù)庫中間件)
人員:運(yùn)維、開發(fā)、測試、產(chǎn)品、等
那接下來我們就來看看從這幾點(diǎn)如何來控制數(shù)據(jù)庫的訪問。
軟件程序?qū)用?/strong>
這里說的軟件程序包含:應(yīng)用程序、數(shù)據(jù)庫中間件等,作為數(shù)據(jù)庫的第一用戶我們?nèi)绾斡行У囊?guī)避數(shù)據(jù)安全的問題呢?
我們先來說說現(xiàn)在的軟件開發(fā)用到的一些框架,無論是java、go、python或其他,已經(jīng)有很豐富的orm和datasource框架或工具,我下面羅列一些java中常用jdbc連接池和orm框架以及數(shù)據(jù)庫中間件
| 名稱 | 說明 | 是否有加解密策略 |
|---|---|---|
| druid | 阿里巴巴開源的數(shù)據(jù)庫連接池 | 有 |
| dbcp | Apache的開源數(shù)據(jù)庫連接池 | 無 |
| c3p0 | 一個(gè)開源的JDBC連接池 | 無 |
| atomikos | 一款分布式事務(wù)框架 | 無 |
| mybatis | 一款開源orm框架 | 無 |
| hibernate | 一款開源orm框架 | 無 |
| mycat | 開源分布式數(shù)據(jù)庫中間件 | 無 |
| shardingsphere | Apache的開源分布式數(shù)據(jù)庫中間件 | 有 |
| cobar | 阿里巴巴開源分片數(shù)據(jù)庫和表的代理 | 有 |
我相信很多程序的數(shù)據(jù)庫連接與密碼都是通過配置文件來保存的,假如應(yīng)用服務(wù)器被黑客利用軟件漏洞拿下,我相信通過部署的軟件可以翻出數(shù)據(jù)庫連接的配置,那么針對這一點(diǎn)我們?nèi)绾斡行У谋苊饽兀?/span>
數(shù)據(jù)庫連接密碼加密
一般我們?yōu)榱俗鰯?shù)據(jù)庫高可用都會給數(shù)據(jù)庫集群中間做一層代理,通過域名的方式來暴漏連接,這樣做的好處就是數(shù)據(jù)庫failover的時(shí)候應(yīng)用程序可以不需要重啟,只用重新創(chuàng)建連接即可。因此這層代理可以有效的防止數(shù)據(jù)庫真實(shí)部署的機(jī)器被暴漏出去,起到了一定的安全作用。
雖然連接層面有一層代理來杜絕真實(shí)服務(wù)器被暴漏,但是我們在通過jdbc連接的時(shí)候往往是有密碼訪問的,我相信很多數(shù)據(jù)庫的密碼是明文的存儲在配置文件中,雖然現(xiàn)在都用配置中心(configcenter)來統(tǒng)一管理應(yīng)用的配置,如果使用明文來保存密碼始終是無法規(guī)避泄漏的風(fēng)險(xiǎn),因?yàn)閼?yīng)用程序始終要進(jìn)行連接,在連接的時(shí)候要讀取配置,不管配置是從云端同步下來還是從本地讀取,只要是明文存儲密碼的就會存在安全問題。
其實(shí)大多的數(shù)據(jù)庫連接池都有對數(shù)據(jù)庫訪問密碼加解密的功能,因此我們可以通過把數(shù)據(jù)庫訪問的密碼進(jìn)行加密來解決安全問題。
下來我使用druid舉個(gè)例子,具體的看看如何使用,也可以查看druid官方?示例
通過使用ConfigFilter為數(shù)據(jù)庫密碼提供加密功能
<bean?id="dataSource"?class="com.alibaba.druid.pool.DruidDataSource"
????????destroy-method="close">
????.................
????
????<property?name="filters"?value="${filters}"?/>
????
????<property?name="filters"?value="stat,config"?/>?
????
????<property?name="connectionProperties"?value="config.decrypt=true;config.decrypt.key=${publickey}"?/>
????.................
bean>
filters=stat
改為
filters=stat,config
jdbc.xxxx.password=123456
改為
jdbc.xxxx.password=加密后的值
增加
publickey=公鑰
ps. 如果使用的是配置中心那么創(chuàng)建對應(yīng)的配置項(xiàng)即可。
非對稱秘鑰對的生成方式有很多種,這里我給個(gè)在線生成的鏈接?加密后的密文是一段比較長的字符,例如下面這段示例
jdbc.password=p9i+fChqlaYnfhI+NoJqmrGwTyWwlFZ1W7Vi7i2MGZ8agFkGxGr/kWU//yDvPyXZ6YwJwnMKQ4zXpTZnfxWaRjfqWIRG+JzxSdSYEMp/bRCiIvzF6y8FdVCqN/0m0eQeZFvMCdIf4wqhKF0QRCEOTysZ3oGg7t5o35CIMpV1A5Y=
其他的jdbc連接池也都有類似的功能,但是不排除有一些沒有這個(gè)功能的就需要我們自己動手開發(fā)來增強(qiáng)這部分功能。
首先我們需要了解數(shù)據(jù)庫連接加解密的思路,只要有思路實(shí)現(xiàn)都是很簡單的,其實(shí)數(shù)據(jù)庫連接加解密思路很簡單,在真正創(chuàng)建數(shù)據(jù)庫連接的時(shí)候讀取加密的密碼進(jìn)行解密后再進(jìn)行數(shù)據(jù)庫連接,那接下來我們給dbcp擴(kuò)展這個(gè)功能。
import?java.sql.SQLFeatureNotSupportedException;
import?java.util.Properties;
import?java.util.logging.Logger;
import?org.apache.commons.dbcp.BasicDataSource;
import?org.slf4j.LoggerFactory;
public?class?SecurityBasicDataSource?extends?BasicDataSource?{
????private?final?org.slf4j.Logger?logger?=?LoggerFactory.getLogger(SecurityBasicDataSource.class);
????@Override
????public?Logger?getParentLogger()?throws?SQLFeatureNotSupportedException?{
????????throw?new?SQLFeatureNotSupportedException();
????}
????@Override
????public?void?setPassword(String?password)?{
????????try?{
????????????//這里可以從任意地方讀取數(shù)據(jù)庫配置
????????????Properties?p?=?ConfigLoaderUtils.loadConfig("jdbc.properties");
????????????String?publickey?=?p.getProperty("publickey");
????????????//ConfigTools是實(shí)現(xiàn)私鑰、公鑰對加解密實(shí)現(xiàn)
????????????password?=?ConfigTools.decrypt(publickey,?password);
????????????super.setPassword(password);
????????}?catch(Exception?e)?{
????????????logger.error("解密password出錯(cuò)",?e);
????????}
????}
}
首先我們繼承
dbcp數(shù)據(jù)源org.apache.commons.dbcp.BasicDataSource重寫
setPassword設(shè)置密碼的時(shí)候通過公鑰和密文進(jìn)行解密
這樣我們就給dbcp擴(kuò)展了數(shù)據(jù)庫連接加解密的功能,是不是很簡單。
到這里我們就對數(shù)據(jù)庫連接密碼加密的方法介紹完畢,這樣做的好處有什么呢?假設(shè)當(dāng)應(yīng)用服務(wù)器被壞人俘虜后,他想通過應(yīng)用的配置信息輕松的獲取數(shù)據(jù)庫訪問密碼是不太可能,采用?公開密鑰加密?安全性還是很高的,它是一種非對稱加密算法想要了解更多的可以點(diǎn)開維基百科的連接查看。
敏感數(shù)據(jù)加解密
前面我們介紹完了數(shù)據(jù)庫連接上的安全問題以及如何解決,接下來我們繼續(xù)介紹數(shù)據(jù)庫中存儲的敏感數(shù)據(jù)應(yīng)該如何處理。
我相信很多人都接觸過導(dǎo)出生產(chǎn)數(shù)據(jù)需要經(jīng)過?數(shù)據(jù)脫敏?,需要經(jīng)過數(shù)據(jù)脫敏的大多都是存儲的明文數(shù)據(jù),比如說用戶的手機(jī)號、詳細(xì)地址、銀行卡號、信用卡驗(yàn)證碼、用戶密碼、等。
如果我們將這些敏感數(shù)據(jù)在存儲入庫的時(shí)候進(jìn)行加密,數(shù)據(jù)庫中存儲的是密文數(shù)據(jù),這樣及時(shí)被脫庫我相信也沒有那么容易破解,有人可能說密碼破解外界有?彩虹表?,彩虹表是一個(gè)用于加密散列函數(shù)逆運(yùn)算的預(yù)先計(jì)算好的表,常用于破解加密過的密碼散列,針對于用戶詳細(xì)地址、銀行卡號我相信彩虹表是無能為力的,如果使用暴力破解時(shí)間上的成本也是難以想象的,可能需要xxxxxx億年,哈哈哈。
我們對數(shù)據(jù)加解密使用對稱加解密算法AES或DES,為什么不使用非對稱的公開密鑰加密??
雖然非對稱加解密算法安全性高,但是非對稱加解密算法加密后的值太長不利于存儲,所以我們需要使用固定長度或者可控長度的加解密算法,剛好對稱加解密算法符合要求,這里使用DES作為示例,當(dāng)然可以替換成任意的加解密算法。
先說說數(shù)據(jù)落庫時(shí)的加解密實(shí)現(xiàn)思路,假設(shè)我們需要存儲用戶詳情,其中有姓名、電話、聯(lián)系地址、銀行卡號等信息,我們在持久化用戶詳情的時(shí)候?qū)γ舾凶侄芜M(jìn)行加密計(jì)算出密文,再將密文存入數(shù)據(jù)庫,當(dāng)查詢用戶詳情的時(shí)候,先從數(shù)據(jù)庫查詢出密文,通過對密文的解密和脫敏再返回給前臺,這樣我們就可以達(dá)到我們想要的效果,這里需要特殊說明一下,密文對模糊查詢不是很友好,但是也可以實(shí)現(xiàn)模糊查詢,具體的實(shí)現(xiàn)思路有很多種,這里我們就不多做介紹,感興趣的話我后面可以單獨(dú)出一篇支持模糊查詢的加解密算法,回到主題我們就以這個(gè)案例進(jìn)行實(shí)現(xiàn)。
首先我們需要對敏感字段進(jìn)行打標(biāo)記,java的annotation可以幫助我們實(shí)現(xiàn)打標(biāo)
import?java.lang.annotation.ElementType;
import?java.lang.annotation.Retention;
import?java.lang.annotation.RetentionPolicy;
import?java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public?@interface?Cipher?{
}
我們可以給用戶對象的敏感字段:手機(jī)號、銀行卡、詳細(xì)地址 上標(biāo)注@Cipher注釋,說明這幾個(gè)字段我們在保存、修改的時(shí)候需要加密,在查詢的時(shí)候需要解密。
下來我們就要找一個(gè)公共的地方來統(tǒng)一的進(jìn)行加解密處理,作為一名合格的程序員需要想盡一切辦法來偷懶,并不是在所有CRUD的地方進(jìn)行加解密調(diào)用這樣會很傻很天真,作為被廣泛使用的orm框架之一的mybatis這里我使用它作為示例講解實(shí)現(xiàn)思路。
mybatis提供攔截器機(jī)制,可以對執(zhí)行的CRUD進(jìn)行攔截處理操作,pagehelper?是一個(gè)分頁的mybatis插件,就是利用攔截的機(jī)制來擴(kuò)展分頁功能。
我們剛才有說過我們需要對insert、update操作進(jìn)行加密,對select操作進(jìn)行解密,在mybatis的底層保存和修改都是update方法,查詢都是query方法,剛好我們就對這兩個(gè)方法進(jìn)行攔截處理。
import?java.lang.reflect.Field;
import?java.util.List;
import?java.util.Properties;
import?org.apache.commons.lang3.StringUtils;
import?org.apache.ibatis.executor.Executor;
import?org.apache.ibatis.mapping.MappedStatement;
import?org.apache.ibatis.plugin.Interceptor;
import?org.apache.ibatis.plugin.Intercepts;
import?org.apache.ibatis.plugin.Invocation;
import?org.apache.ibatis.plugin.Plugin;
import?org.apache.ibatis.plugin.Signature;
import?org.apache.ibatis.session.ResultHandler;
import?org.apache.ibatis.session.RowBounds;
import?org.apache.ibatis.session.defaults.DefaultSqlSession.StrictMap;
import?org.slf4j.Logger;
import?org.slf4j.LoggerFactory;
@Intercepts({
????????@Signature(type?=?Executor.class,?method?=?"update",?args?=?{?MappedStatement.class,?Object.class?}),
????????@Signature(type?=?Executor.class,?method?=?"query",?args?=?{?MappedStatement.class,?Object.class,
????????????????RowBounds.class,?ResultHandler.class?})?})
public?class?CipherHelper?implements?Interceptor?{
????private?final?Logger?logger?=?LoggerFactory.getLogger(CipherHelper.class);
????/**
?????*?加密密鑰br>?為null,使用默認(rèn)密鑰進(jìn)行加解密br>
?????*/
????private?String?secureKey?=?null;
????/**
?????*?是否允許寬容處理br>?寬容處理的話,使用原值,反之throw?{@link?CipherException}br>
?????*/
????private?boolean?lenient?=?false;
????@Override
????public?Object?intercept(Invocation?invocation)?throws?Throwable?{
????????String?methodName?=?invocation.getMethod().getName();
????????if?(methodName.equals("update")?||?methodName.equals("query"))?{
?????????????Object?parameter?=?invocation.getArgs()[1];
????????????if?(parameter?instanceof?List)?{
????????????????List>?list?=?(List>)?parameter;
????????????????for?(Object?obj?:?list)?{
????????????????????encrypt(obj);
????????????????}
????????????}?else?if(parameter?instanceof?StrictMap)?{
????????????????StrictMap>?strictMap?=?(StrictMap>)?parameter;
????????????????if?(strictMap.containsKey("list"))?{
????????????????????List>?list?=?(List>)?strictMap.get("list");
????????????????????for?(Object?obj?:?list)?{
????????????????????????encrypt(obj);
????????????????????}
????????????????}?else?if?(strictMap.containsKey("array"))?{
????????????????????Object[]?objects?=?(Object[])?strictMap.get("array");
????????????????????for?(Object?obj?:?objects)?{
????????????????????????encrypt(obj);
????????????????????}
????????????????}
????????????}?else?{
????????????????encrypt(parameter);
????????????}
????????}
????????Object?returnValue?=?invocation.proceed();
????????if?(methodName.equals("query"))?{
????????????if?(returnValue?instanceof?List)?{
????????????????List>?list?=?(List>)?returnValue;
????????????????for?(Object?obj?:?list)?{
????????????????????decrypt(obj);
????????????????}
????????????}?else?{
????????????????decrypt(returnValue);
????????????}
????????}
????????return?returnValue;
????}
????/**
?????*?加密處理
?????*?
?????*?@param?parameter
?????*?@throws?IllegalAccessException
?????*/
????private?void?encrypt(Object?parameter)?throws?IllegalAccessException?{
????????if?(parameter?==?null)?return;
????????Class>?clazz?=?parameter.getClass();
????????if?(!clazz.getSimpleName().endsWith("Entity"))?{
????????????return;
????????}
????????for?(;?clazz?!=?Object.class;?clazz?=?clazz.getSuperclass())?{
????????????Field[]?fields?=?clazz.getDeclaredFields();
????????????for?(int?i?=?0;?i?????????????????if?(!fields[i].isAnnotationPresent(Cipher.class))?{
????????????????????continue;
????????????????}
????????????????if?(!fields[i].getType().equals(String.class))?{
????????????????????logger.debug("加密字段只支持String類型,當(dāng)前類型非String,跳過!");
????????????????????continue;
????????????????}
????????????????fields[i].setAccessible(true);
????????????????String?v?=?(String)?fields[i].get(parameter);
????????????????if?(StringUtils.isBlank(v))?{
????????????????????logger.debug("加密字段值為null,跳過!");
????????????????????continue;
????????????????}
????????????????try?{
????????????????????String?crypt?=?DESTools.encrypt(secureKey,?v);
????????????????????fields[i].set(parameter,?crypt);
????????????????????logger.debug("加密處理字段,{}",?fields[i].getName());
????????????????}?catch?(Exception?e)?{
????????????????????if?(lenient)?{
????????????????????????logger.warn("加密處理失敗,寬容處理使用原值");
????????????????????}?else?{
????????????????????????throw?new?CipherException("加密處理失敗,不允許寬容處理["+v+"]",?e);
????????????????????}
????????????????}
????????????}
????????}
????}
????/**
?????*?解密處理
?????*?
?????*?@param?obj
?????*?@throws?IllegalAccessException
?????*?@throws?Exception
?????*/
????private?void?decrypt(Object?obj)?throws?IllegalAccessException,?Exception?{
????????if?(obj?==?null)?return;
????????Class>?clazz?=?obj.getClass();
????????if?(!clazz.getSimpleName().endsWith("Entity"))?{
????????????return;
????????}
????????for?(;?clazz?!=?Object.class;?clazz?=?clazz.getSuperclass())?{
????????????Field[]?fields?=?clazz.getDeclaredFields();
????????????for?(int?i?=?0;?i?????????????????if?(!fields[i].isAnnotationPresent(Cipher.class))?{
????????????????????continue;
????????????????}
????????????????if?(!fields[i].getType().equals(String.class))?{
????????????????????logger.debug("解密字段只支持String類型,當(dāng)前類型非String,跳過!");
????????????????????continue;
????????????????}
????????????????fields[i].setAccessible(true);
????????????????String?v?=?(String)?fields[i].get(obj);
????????????????if?(StringUtils.isBlank(v))?{
????????????????????logger.debug("解密字段值為null,跳過!");
????????????????????continue;
????????????????}
????????????????try?{
????????????????????String?crypt?=?DESTools.decrypt(secureKey,?v);
????????????????????fields[i].set(obj,?crypt);
????????????????????logger.info("解密處理字段,{}",?fields[i].getName());
????????????????}?catch?(Exception?e)?{
????????????????????if?(lenient)?{
????????????????????????logger.warn("解密處理失敗,寬容處理使用原值");
????????????????????}?else?{
????????????????????????throw?new?CipherException("解密處理失敗,不允許寬容處理["+v+"]",?e);
????????????????????}
????????????????}
????????????}
????????}
????}
????@Override
????public?Object?plugin(Object?target)?{
????????return?Plugin.wrap(target,?this);
????}
????@Override
????public?void?setProperties(Properties?properties)?{
????????if?(properties?!=?null?&&?StringUtils.isNotBlank(properties.getProperty("secureKey")))?{
????????????this.secureKey?=?properties.getProperty("secureKey");
????????}
????????if?(properties?!=?null?&&?StringUtils.isNoneBlank(properties.getProperty("lenient")))?{
????????????this.lenient?=?Boolean.parseBoolean(properties.getProperty("lenient"));
????????}
????}
}
通過mybatis的插件擴(kuò)展機(jī)制在執(zhí)行過程進(jìn)行攔截處理,plugin方法是插件的裝載方法,setProperties方法設(shè)置關(guān)鍵屬性,比如說密鑰串。
接下來我們對每個(gè)方法進(jìn)行講解:
encrypt:是加密方法,這里加密方法需要注意的是,mybatis參數(shù)支持Pojo?、Map、StrictMap、List、Array,我們使用注解@Cipher是用在類上的所以只對Pojo生效,如果是Map它天生的key,value格式無法支持打標(biāo),我們這里對Map類型進(jìn)行跳過不處理,如果非要處理Map也是有辦法的,需要固定加解密的key值,對特定的key進(jìn)行識別并加解密替換value,加密方法通過查找有注解@Cipher的字段進(jìn)行加密并且回填值。
decrypt:是解密方法,主要用在查詢時(shí)的解密,這里需要注意的是查詢有可能返回特定的Pojo也可能返回List,所以這里解密的時(shí)候需要根據(jù)類型來分別處理,如果是List需要進(jìn)行很層次查找,如果是Pojo那就查找使用注解@Cipher的字段進(jìn)行解密并且回填值。
intercept:是攔截方法,在update、query前后進(jìn)行攔截處理,在這個(gè)方法里需要進(jìn)行如下步驟:
識別當(dāng)前執(zhí)行的
method是update還是query如果是
update那就進(jìn)行加密如果是
query那就進(jìn)行解密識別參數(shù)類型是
List、StrictMap、Pojo如果
StrictMap里是list那就循環(huán)調(diào)用encrypt方法如果
StrictMap里是array那就循環(huán)調(diào)用encrypt方法如果
List里是Pojo那就循環(huán)調(diào)用encrypt方法如果
List里是Map跳過處理,或者使用上面我們說的識別某些固定key進(jìn)行加密處理如果是
List需要再深層次看一下List里是什么類型,這里建議使用遞歸方式如果是
StrictMap需要再深層次看一下StrictMap里是什么類型,這里建議使用遞歸方式如果是
Pojo那就調(diào)用encrypt方法執(zhí)行sql處理獲取返回值
獲取返回值并且執(zhí)行的方法是
query時(shí),進(jìn)行解密處理如果是
List深層次查找內(nèi)部類型,這里建議使用遞歸方式如果是
Pojo那就調(diào)用decrypt方法如果
List里是Pojo那就循環(huán)調(diào)用decrypt方法如果
List里是Map跳過處理,或者使用上面我們說的識別某些固定key進(jìn)行解密處理識別返回的類型是
List還是Pojo
到這里數(shù)據(jù)加解密的核心邏輯就介紹完了。
這里我們回顧一下,我們先是對數(shù)據(jù)庫連接密碼進(jìn)行加解密,然后又對敏感數(shù)據(jù)落庫和查詢時(shí)進(jìn)行加解密,第一步連接密碼加密預(yù)防壞人即使攻擊拿到了應(yīng)用服務(wù)器的操作權(quán)限他也無法輕易的攻克我們的數(shù)據(jù)庫訪問密碼,第二步敏感數(shù)據(jù)加解密預(yù)防壞人即使攻克了我們的數(shù)據(jù)庫(俗稱脫庫)他也無法獲取用戶的隱私數(shù)據(jù),這樣就有效的保證了用戶隱私數(shù)據(jù)的安全性。
到這里我們就對軟件程序?qū)用娴臄?shù)據(jù)安全防護(hù)手段介紹完畢,接下來我們再從人員訪問控制方面來看看有什么有效的手段。
人員層面
前面我們說了絕大多數(shù)的數(shù)據(jù)泄密都不是技術(shù)問題而是人員管理問題,我們要對人員進(jìn)行有效的管理與控制。
開發(fā)或測試人員
這類人一般對數(shù)據(jù)是有CRUD的訴求,針對這類人員的控制有如下幾個(gè)方面
開發(fā)人員只能連接測試環(huán)境數(shù)據(jù)庫,不允許連接生產(chǎn)數(shù)據(jù)庫,即使連接vpn也不行。
開發(fā)人員申請數(shù)據(jù)庫需要走運(yùn)維工單流程,運(yùn)維提供數(shù)據(jù)庫連接密碼時(shí)應(yīng)直接提供密文,或者運(yùn)維直接給配置到配置中心。
配置文件或配置中心禁止存儲明文密碼,需要對jdbc等其他敏感密碼進(jìn)行脫敏處理。
生產(chǎn)服務(wù)器需要通過跳板機(jī)訪問,禁止開發(fā)使用
root直接操作,如果看應(yīng)用日志可以走日志平臺,實(shí)在沒有日志平臺可以給跳板機(jī)開通app用戶只給查看固定目錄日志的權(quán)限,如果要發(fā)布走devops平臺,如果沒有可以提供給運(yùn)維進(jìn)行發(fā)布。查詢生產(chǎn)數(shù)據(jù)走
dms平臺,對敏感信息進(jìn)行脫敏或隱藏,對上線的sql和日常的查詢?nèi)罩咀龅?/span>dms可管控。提交到開放環(huán)境時(shí)需要注意以下幾點(diǎn)
提交到開放的倉庫(
github、gitlab、gitee等),需要對代碼進(jìn)行審核,避免有hardcode的公司服務(wù)器密碼、ip、端口、密鑰等。提交到開放的論壇(
csdn、oschina、知乎、公眾號、社區(qū)分享等),需要對文章進(jìn)行審核,避免有不允許公開的技術(shù)細(xì)節(jié)或敏感信息。
運(yùn)維或DBA人員
這類人一般操作權(quán)限都很高,出問題概率最高的人員,有很多刪庫跑路或誤操作rm -rf的例子哈哈哈!所以這類人更要重點(diǎn)管控。
需要搭建和處理運(yùn)維工單平臺,用于開發(fā)提出的運(yùn)維資源申請,尤其是數(shù)據(jù)庫密碼,直接提供加密后的密文和公鑰。
需要搭建和處理數(shù)據(jù)庫管理工具
dms,用于開發(fā)日常生產(chǎn)數(shù)據(jù)查詢和發(fā)版時(shí)SQL升級。需要提供跳板機(jī)和給跳板機(jī)提供不同等級的用戶,提供給特別需要的人訪問生產(chǎn)環(huán)境機(jī)器。
需要提供
devops平臺或者自動化發(fā)版工具,避免手動操作失誤帶來問題,對開發(fā)提供升級發(fā)布的流水線。對服務(wù)器密碼需要進(jìn)行加密存儲,可以借助密碼管理工具。
運(yùn)維最好也不要使用
root用戶操作服務(wù)器,使用特定權(quán)限的用戶操作。dba最好也不要使用root用戶操作數(shù)據(jù)庫,使用特定權(quán)限的用戶操作。制定責(zé)任人機(jī)制,對應(yīng)的責(zé)任項(xiàng)必須到具體人,具體可以參考?責(zé)任分配矩陣RAM?。
關(guān)鍵重要的操作需要至少兩個(gè)人在場,具體可以參考?責(zé)任分配矩陣RAM?。
產(chǎn)品或業(yè)務(wù)人員
這類人一般對數(shù)據(jù)有查詢和分析的訴求,有分析訴求就需要導(dǎo)出數(shù)據(jù),所以分析訴求統(tǒng)一走公司BI工具,也有少部分有修改的訴求。
查詢分析數(shù)據(jù),統(tǒng)一接入
BI工具,并且BI工具需要有功能和數(shù)據(jù)權(quán)限,并對敏感數(shù)據(jù)導(dǎo)出加以控制,導(dǎo)出走審批并脫敏。提交數(shù)據(jù)變更,統(tǒng)一接入
dms平臺。產(chǎn)品的分析文件(word、excel、ppt)應(yīng)該進(jìn)行加密,這種一般依賴公司引入文檔安全的解決方案,要花錢的,如果不想花錢那就沒啥好辦法。
總結(jié)
到這里整篇也就差不多都介紹完了,我們現(xiàn)在回顧一下,首先我們介紹了數(shù)據(jù)安全的問題,并且說明了安全問題一般發(fā)生在兩個(gè)方面,一個(gè)是軟件程序,一個(gè)是人員管理。
我們在軟件程序方面介紹了兩種預(yù)防數(shù)據(jù)安全的手段,一個(gè)是數(shù)據(jù)庫連接密碼加解密,一個(gè)是數(shù)據(jù)加解密,數(shù)據(jù)庫連接加密可以有效預(yù)防服務(wù)器被攻擊后通過翻找程序來進(jìn)一步攻擊數(shù)據(jù)庫,數(shù)據(jù)加解密可以有效預(yù)防數(shù)據(jù)庫被攻擊或脫庫后泄漏用戶及公司隱私數(shù)據(jù)。
我們在人員方面首先對人員進(jìn)行了分類,針對每一類人的訴求談了管控的手段,說了這么多的控制手段,并不是說對員工不信任,這里說的控制并不等于限制,說了這么多的終極目標(biāo)是搭建一套有序的安全的管理機(jī)制,在安全的范圍內(nèi)給員工提供最大化的發(fā)揮空間,規(guī)避有心或無心的泄密。
source: //ningyu1.github.io/20201229/datasource-security.html

喜歡,在看
