电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術(shù)文章
文章詳情頁

編寫安全的SQL server擴展存儲過程

瀏覽:161日期:2023-10-29 16:18:53

SQL server 的擴展存儲過程,其實就是一個普通的 windows DLL,只不過按照某種規(guī)則實現(xiàn)了某些函數(shù)而已。

近日在寫一個擴展存儲過程時,發(fā)現(xiàn)再寫這類動態(tài)庫時,還是有一些需要特別注意的地方。之所以會特別注意,是因為DLL運行于SQL server的地址空間,而SQL Server到底是怎么進行線程調(diào)度的,卻不是我們能了解的,即便了解也無法控制。

我們寫動態(tài)庫一般是自己用,即便給別人用,也很少像SQL Server這樣,一個動態(tài)庫很有可能加載多次,并且都是加載到一個進程的地址空間中。我們知道,當一個動態(tài)庫加載到進程的地址空間時,DLL所有全局與局部變量初始化且僅初始化一次,以后再次調(diào)用 LoadLibrary函數(shù)時,僅僅增加其引用計數(shù)而已,那么很顯然,假如有一全局 int ,初始化為0,調(diào)用一個函數(shù)另其自加,此時其值為1,然后再調(diào)用LoadLibray,并利用返回的句柄調(diào)用輸出函數(shù)輸出該值,雖然調(diào)用者覺得自己加載后立即輸出,然后該值確實1而不是0。windows是進程獨立的,而在線程方面,假如不注意,上面的情況很可能會程序員帶來麻煩。

介紹一下我的擴展存儲過程,該動態(tài)庫導出了三個函數(shù): Init,work,Final,Init讀文件,存儲信息于內(nèi)存,work簡單的只是向該內(nèi)存檢索信息,Final回收內(nèi)存。如上所說,假如不考慮同一進程空間多次加載問題,兩次調(diào)用Init將造成無謂的浪費,因為我第一次已經(jīng)讀進了內(nèi)存,要是通過堆分配內(nèi)存,還會造成內(nèi)存泄露。

我使用的引用計數(shù)解決的該問題,代碼很短,直接貼上來:

#include 'stdafx.h'#include; <string>

using namespace std;

extern 'C' {RETCODE __declspec(dllexport) xp_part_init(SRV_PROC *srvproc);RETCODE __declspec(dllexport) xp_part_process(SRV_PROC *srvproc);RETCODE __declspec(dllexport) xp_part_finalize(SRV_PROC *srvproc);}

#define XP_NOERROR;;;0#define XP_ERROR;;;;;1

HINSTANCE hInst = NULL;int nRef = 0;

void printError (SRV_PROC *pSrvProc, CHAR* szErrorMsg);

ULONG __GetXpVersion(){ return ODS_VERSION;}

SRVRETCODE xp_part_init(SRV_PROC* pSrvProc){typedef bool (*Func)();

if(nRef == 0){ hInst = ::LoadLibrary('part.dll'); if(hInst == NULL){ printError(pSrvProc,'不能加載part.dll'); return XP_ERROR; } Func theFunc = (Func)::GetProcAddress(hInst,'Init'); if(!theFunc()){ ::FreeLibrary(hInst); printError(pSrvProc,'不能獲得分類號與專輯的對應表'); return XP_ERROR; }}

++ nRef;return (XP_NOERROR);}

SRVRETCODE xp_part_process(SRV_PROC* pSrvProc){typedef bool (*Func)(char*);if(nRef == 0){ printError(pSrvProc,'函數(shù)尚未初始化,請首先調(diào)用xp_part_init'); return XP_ERROR;}Func theFunc = (Func)::GetProcAddress(hInst,'Get');

BYTE bType;ULONG cbMaxLen,cbActualLen;BOOL fNull;char szInput[256] = {0};

if (srv_paraminfo(pSrvProc, 1, &bType, (ULONG*)&cbMaxLen, (ULONG*)&cbActualLen, (BYTE*)szInput, &fNull) == FAIL){ printError(pSrvProc,'srv_paraminfo 返回 FAIL'); return XP_ERROR;}szInput[cbActualLen] = 0;

string strInput = szInput;string strOutput = ';';int cur,old = 0;while(string::npos != (cur = strInput.find(';',old)) ){ strncpy(szInput,strInput.c_str() + old,cur - old); szInput[cur - old] = 0; old = cur + 1; theFunc(szInput);

if(string::npos ==strOutput.find((string)';' + szInput)) strOutput += szInput;}

strcpy(szInput,strOutput.c_str());if (FAIL == srv_paramsetoutput(pSrvProc, 1, (BYTE*)(szInput + 1), strlen(szInput) - 1,FALSE)){ printError (pSrvProc, 'srv_paramsetoutput 調(diào)用失敗'); return XP_ERROR;}

srv_senddone(pSrvProc, (SRV_DONE_COUNT | SRV_DONE_MORE), 0, 0);return XP_NOERROR;}

SRVRETCODE xp_part_finalize(SRV_PROC* pSrvProc){typedef void (*Func)();

if(nRef == 0) return XP_NOERROR;Func theFunc = (Func)::GetProcAddress(hInst,'Fin');

if((--nRef) == 0){ theFunc(); ::FreeLibrary(hInst); hInst = NULL;}return (XP_NOERROR);}

我想雖然看上去不是很高明,然而問題應該是解決了的。

還有一點說明,為什么不使用Tls,老實說,我考慮過使用的,因為其實代碼是有一點問題的,假如一個用戶調(diào)用xp_part_init,然后另一個用戶也調(diào)用xp_part_init,注意我們的存儲過程可是服務器端的,然后第一個用戶調(diào)用xp_part_finalize,那么會怎樣,他仍然可以正常使用xp_part_process,這倒無所謂,然而第一個用戶調(diào)用兩次xp_part_finalize,就能夠影響第二個用戶了,他的xp_part_process將返回錯誤。

使用Tls 似乎可以解決這問題,例如再添加一個tls_index變量,調(diào)用 TlsSetValue保存用戶私人數(shù)據(jù),TlsGetValue檢索私人數(shù)據(jù),當xp_part_init時,假如該私人數(shù)據(jù)為0,執(zhí)行正常的初始化過程,(即上面的xp_part_init)執(zhí)行成功后存儲私人數(shù)據(jù)為1,假如是1,直接返回,xp_part_finalize時,假如私人數(shù)據(jù)為1,則執(zhí)行正常的xp_part_finalize,然后設(shè)私人數(shù)據(jù)為0,假如是0,直接返回。

好像想法還是不錯的,這樣隔離了多個用戶,安全性似乎提高了不少,然而事實是不可行的。因為Tls保存的并不是私人數(shù)據(jù),而是線程本地變量,我們不能保證一個用戶的多次操作都是用同一個線程執(zhí)行的,這個由SQL Server自己控制,事實上我在查詢分析器里多次執(zhí)行的結(jié)果顯示,SQL Server內(nèi)部似乎使用了一個線程池。既然如此,那這種想法也只能作罷。

標題叫 編寫安全的SQL server擴展存儲過程,其實還是很不安全,除非調(diào)用者嚴格遵守 Init與Finalize的配對原則,幸運的是,這個是程序員可以控制的,只要遵守這個原則,那就是安全的。

主站蜘蛛池模板: YAGEO国巨电容|贴片电阻|电容价格|三星代理商-深圳市巨优电子有限公司 | 美国查特CHART MVE液氮罐_查特杜瓦瓶_制造全球品质液氮罐 | 武汉印刷厂-不干胶标签印刷厂-武汉不干胶印刷-武汉标签印刷厂-武汉标签制作 - 善进特种标签印刷厂 | 沈阳网站建设_沈阳网站制作_沈阳网页设计-做网站就找示剑新零售 沈阳缠绕膜价格_沈阳拉伸膜厂家_沈阳缠绕膜厂家直销 | 福州时代广告制作装饰有限公司-福州广告公司广告牌制作,福州展厅文化墙广告设计, | 压片机_高速_单冲_双层_花篮式_多功能旋转压片机-上海天九压片机厂家 | 诺冠气动元件,诺冠电磁阀,海隆防爆阀,norgren气缸-山东锦隆自动化科技有限公司 | 【连江县榕彩涂料有限公司】官方网站 | 酒精检测棒,数显温湿度计,酒安酒精测试仪,酒精检测仪,呼气式酒精检测仪-郑州欧诺仪器有限公司 | 篮球地板厂家_舞台木地板品牌_体育运动地板厂家_凯洁地板 | 网站优化公司_北京网站优化_抖音短视频代运营_抖音关键词seo优化排名-通则达网络 | 千淘酒店差旅平台-中国第一家针对TMC行业的酒店资源供应平台 | 食安观察网| 无纺布包装机|径向缠绕包装机|缠绕膜打包机-上海晏陵智能设备有限公司 | 营养师网,营养师考试时间,报名入口—网站首页 | 无线联网门锁|校园联网门锁|学校智能门锁|公租房智能门锁|保障房管理系统-KEENZY中科易安 | 深圳天际源广告-形象堆头,企业文化墙,喷绘,门头招牌设计制作专家 | 家德利门业,家居安全门,别墅大门 - 安徽家德利门业有限公司 | 吸污车_吸粪车_抽粪车_电动三轮吸粪车_真空吸污车_高压清洗吸污车-远大汽车制造有限公司 | 路面机械厂家| 洛阳防爆合格证办理-洛阳防爆认证机构-洛阳申请国家防爆合格证-洛阳本安防爆认证代办-洛阳沪南抚防爆电气技术服务有限公司 | 超声波清洗机_超声波清洗机设备_超声波清洗机厂家_鼎泰恒胜 | 安徽千住锡膏_安徽阿尔法锡膏锡条_安徽唯特偶锡膏_卡夫特胶水-芜湖荣亮电子科技有限公司 | GAST/BRIWATEC/CINCINNATI/KARL-KLEIN/ZIEHL-ABEGG风机|亚喜科技 | 视频教程导航网_视频教程之家_视频教程大全_最新视频教程分享发布平台 | 电缆接头-防爆电缆接头-格兰头-金属电缆接头-防爆填料函 | 杭州厂房降温,车间降温设备,车间通风降温,厂房降温方案,杭州嘉友实业爽风品牌 | 无菌检查集菌仪,微生物限度仪器-苏州长留仪器百科 | 噪声治理公司-噪音治理专业隔音降噪公司 | 济南ISO9000认证咨询代理公司,ISO9001认证,CMA实验室认证,ISO/TS16949认证,服务体系认证,资产管理体系认证,SC食品生产许可证- 济南创远企业管理咨询有限公司 郑州电线电缆厂家-防火|低压|低烟无卤电缆-河南明星电缆 | 自动记录数据电子台秤,记忆储存重量电子桌称,设定时间记录电子秤-昆山巨天 | 超细|超微气流粉碎机|气流磨|气流分级机|粉体改性机|磨粉机|粉碎设备-山东埃尔派粉体科技 | ptc_浴霸_大巴_干衣机_呼吸机_毛巾架_电动车加热器-上海帕克 | 杰福伦_磁致伸缩位移传感器_线性位移传感器-意大利GEFRAN杰福伦-河南赉威液压科技有限公司 | 长沙网站建设制作「网站优化推广」-网页设计公司-速马科技官网 | 湖南成人高考报名-湖南成考网| 西安展台设计搭建_西安活动策划公司_西安会议会场布置_西安展厅设计西安旭阳展览展示 | 钢木实验台-全钢实验台-化验室通风柜-实验室装修厂家-杭州博扬实验设备 | 厌氧反应器,IC厌氧反应器,厌氧三相分离器-山东创博环保科技有限公司 | 火锅加盟_四川成都火锅店加盟_中国火锅连锁品牌十强_朝天门火锅【官网】 | 顶空进样器-吹扫捕集仪-热脱附仪-二次热解吸仪-北京华盛谱信仪器 |