数学建模社区-数学中国

标题: socket连接多层程序安全性简述 - 连接 [打印本页]

作者: 韩冰    时间: 2005-1-26 01:08
标题: socket连接多层程序安全性简述 - 连接

4 ~3 Q; r2 ?* d/ J! K1 W/ r

前面hawkfly提到的在多层编程中,服务器端安全性验证的问题

; u( |0 g+ a' i2 P3 K

在以socket方式实现MIDAS时尤为明显,DCOM/CORBA都有现成的

# B1 z5 C* V8 I

安全管理功能,而socket方式在这方面比较薄弱,没有现成的解决方案

8 k6 ~1 w( y! Y1 X' }: O- J

现就我以前对MIDAS编程的理解,做一个简要的介绍,

/ M3 e0 w8 e( D/ \

以后有时间精力再详细举例说明

" g; \# f! B. B8 \5 _5 w5 x7 Z

( X+ t9 Z0 M# z3 P) s

win2k中dcom的安全级别有7种,其中

6 @$ ^/ S) ?: }. E: Z# K; P

最低的“无”安全检查暂且不论

! f) }1 s1 g9 K+ Q0 P* P& g

默认的“身份验证”服务方式几句话也说不清,

& ^: W' G" G) J! R

先放到一边,看看剩下的5种

; G+ u2 C1 ^8 P" c6 V& @, ~

4 q7 N0 B8 O$ V; @( q- `9 ^

1.连接,仅对初始连接进行安全检查

3 C: v0 \$ o- T& |4 V. f6 c

# s6 @6 w* Z& G; f6 [, v/ f8 S# p/ U5 o

因为tcp/ip是稳固的连接,因此每个连接,也就是每个RemoteDataModule

% a$ Z9 A( e6 G$ m

实例检测一次即可,实现方法很多,这里简要介绍一种最简单的

/ J+ n( b* _$ @0 O/ z9 N6 F) j/ k

可以在服务器端的TypeLibrary里面为你的服务器接口增加若干个方法,如

* u, k- h% D5 i$ R/ }

interface ILoginServer: IAppServer

: ?' g8 {5 ?" c4 a* s9 W

{

; ^& G0 V0 J$ w( Y6 V" @& b2 I

[

& w) r$ _1 d3 R% e- j/ j& u

id(0x00000001)

/ z: \) z3 |; {% j- R) \) m! c7 ^

]

2 G, W5 X/ B8 l' P5 q5 I7 {$ @

HRESULT _stdcall Login( void );

J) f' |" p, i- I! I! k

[

; U8 i% B6 \+ s% N. ^2 f

id(0x00000002)

. o/ \3 |5 w: T7 K* A0 p

]

0 `; o d9 C; Q* n' {1 d" q1 \

HRESULT _stdcall Logout( void );

9 _3 C$ y% m; T6 P2 Y. O/ Z

};

. C9 B) V" @4 `& z8 X- {/ n

在方法中实现你的客户身份校验,而在校验之前,通过把RDM上所有的TDataSetProvider

6 J" K- P6 S- _# A4 E. s. d

的Exported属性关掉即可让客户端无法看到服务器端的provider

0 N; ~' C8 L; {5 s7 v

因为客户端实际上是在连接服务器成功后通过服务器之IAppServer接口访问

( K# w( V2 {# O: u6 N

所有的Provider,如IAppServer::AS_GetProviderNames可以取得

% v& c, K; V0 |" J* u' u* R8 X; V

服务器端所有exported的IProvider接口名称,而所有数据的取得、修改

0 A5 P% t9 S; j. d3 D' h

都是通过相应的ProviderName来指定的,如

- [+ B7 T9 H1 t1 r

virtual HRESULT __safecall AS_GetRecords(const WideString: ProviderName, in

/ t* ~, i! ` V3 l' F0 |

t Count, int &RecsOut, int Options, const WideString: CommandText, OleVarian

/ ?) d0 `. D# V1 s/ H( S7 n

t &arams, OleVariant: &OwnerData, OleVariant &GetRecords_result) = 0 ;

7 C; F8 G+ o S8 @) f- l

取得数据方法的第一个参数就是你需要操作的数据集名称……

2 N) B7 ]* m/ {' ^; i- t" L5 [

如果你把服务器RDM上所有的TDataSetProvider::Exported关掉,

/ }. a: N' f8 l2 u. N9 H2 a

则客户端看不到任何Provider,也无法通过其ProviderName取得数据

$ K3 H9 l: _; D) ^7 P

例如我在服务器端的RDM类中加入

" U0 r/ b8 D2 z, @

class TLoginServer : public TCRemoteDataModule

) G9 t# i5 q* x, o9 d

{

! R K; E7 I1 j, O& \/ x! u% k

...

- h3 D @* ]% c. }7 r7 r' u" A

private: // User declarations

+ }% h0 @( a6 D8 P7 M! R3 r

bool FLogin;

" i" q7 h) U# r1 l) B8 X

void __fastcall SetLogin(bool value);

8 z3 w5 z4 i$ m- l, ~" X9 b0 x

bool __fastcall IsLogin(OleVariant &OwnerData);

' R1 {; D1 f# x! F( c

...

3 I; \: N; ]4 ]

__published:

' K5 {( P- V2 o2 ~8 ~( X

__property bool Login = { read = FLogin, write = SetLogin };

4 Y% o! W* e, }( d+ m, g3 ^5 [5 {+ R

};

. N2 h# h& y# h$ D( n) N' U8 S

在RDM实现类中

5 H# P4 |( i& ]+ ?7 u

class ATL_NO_VTABLE TLoginServerImpl: 。。。

2 W1 F( h: K. Q

{

% ~& V2 ~ B& D1 q% Q9 k

// ILoginServer

3 q k( z: |* R; F

protected:

: J% _$ F& t- R' a/ X; z

STDMETHOD(Login());

" z2 e' P) r- E

STDMETHOD(Logout());

3 X) p0 r/ {9 N& H0 y

};

) K" e& X# b% \$ M( T+ H& T- @

然后简单实现之

9 Y& X5 e% x- P4 e

__fastcall TLoginServer::TLoginServer(TComponent* Owner)

' _7 e+ q, \, R u

: TCRemoteDataModule(Owner), FLogin(false)

( X% f/ n) L9 k% D. }

{

9 U/ c/ ]" D' \: E/ s2 X4 H' M: o

}

8 G$ |2 B- _5 E7 U# V# t

//---------------------------------------------------------------------------

; x D' V2 F+ z, N$ J

void __fastcall TLoginServer::SetLogin(bool value)

s; U9 ~/ G9 a

{

/ o' Y; s- t) q0 D: ]: n

if(FLogin != value)

9 |8 M" P5 ?9 |0 Y( Z. {! b- M

{

* ^0 l: Y3 ]9 }1 [( J

FLogin = value;

# x" I% X+ e; R4 k, _

dspAnimals->Exported = FLogin;

, _& A- Q/ ], R$ e9 K

}

) H0 W1 _3 P4 [1 p

}

M0 m7 `6 Z; s# k+ M

//---------------------------------------------------------------------------

, U9 u: R% c4 k! Y

STDMETHODIMP TLoginServerImpl:ogin()

; F* I S! C% Y& v

{

. r; ~4 A1 s9 h9 v5 w4 b

m_DataModule->Login = true;

+ r4 G$ Z' c( T$ T: I6 f

return S_OK;

6 A* {) k$ N8 }3 e: p, N% [

}

: R- B3 T8 |( s

//---------------------------------------------------------------------------

0 j% `: K" i" `5 S5 R7 j

STDMETHODIMP TLoginServerImpl:ogout()

# N/ q* k" w3 m1 W0 J5 T6 F

{

; M- I4 W9 _7 L4 D; d

m_DataModule->Login = false;

2 K2 ?$ v% j% r& x

return S_FALSE;

2 F, g- c+ E0 A$ v. r& m

}

$ `$ R" T/ \2 n, m7 c

//---------------------------------------------------------------------------

' i: c/ r" k3 ?# g- _/ S

bool __fastcall TLoginServer::IsLogin(OleVariant &OwnerData)

8 A) N9 x& T: l- S# c% }

{

% \/ T: E& G$ Y- X( l

return FLogin;

7 B5 b/ T N6 z" e' m1 @9 M% ?" f5 u

}

0 R( X' G& b; _" G6 ?

easy 这样除非你的客户端成功调用Login方法,否则他是无法使用

% Y" [; @% x" {. `8 X4 `4 J

dspAnimals这个数据集Provider的,成功调用后手工打开的数据集使用完全相同

( s% ], l! b+ y5 n* {4 Y* t# J! g

4 u& b2 J- A, ]/ k( k8 C

比如客户端可以用如下代码

+ s# t1 i' ?; l0 |# e' O. z% d

IDispatch *dispAppServer = (IDispatch*)(DM->Connection->AppServer);

4 S5 e% ]$ j" r+ T8 F$ E$ J

ILoginServerDisp dispLoginServer = (ILoginServer *)dispAppServer;

5 z# M% _& N6 C! {* _" p/ W. X

dispLoginServer.Login();

0 }" r \) n) l7 _3 i1 S

DM->cdsAnimals->Open();

7 _! H# h' u- ~- ]

实现注册,并且打开相应数据集……

$ |2 v1 v. z& D/ q* A3 L

' j( F1 s C% Z% G( v" |

因为大多数的三层程序对安全性要求并不高,因此这样的安全检测对

8 b8 _1 E/ H' X, y6 d% _. A

绝大多数程序应该足以……






欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5