Farseer

导航

Writing Secure X++ Code(一)

从微软的网站上下了最新的技术文档,Writing Secure X++ Code,边看边Mark一下.
CAS(Code Access Security)
why?
CAS通过一下措施为调用有危险的APIs提供保护.
1.它保证未经确认的代码使用危险APIs时在调用堆栈上有恰当的权限.
2.它保证使用危险APIs的请求执行在安全代码并保存在AOT中.
3.它保证使用危险APIs的代码跟危险APIS运行在同一层.
感觉真像绕口令,就是把使用带有一定危险性的APIs的代码放在一个安全的地方,执行在一定的地方,提供一定的安全保障机制.
Axapta4.0的CAS机制把有危险性的API的调用都限定在了AOS上,所以不必费心劳力地去照顾客户端了.
how?
CAS必须有APIs的拥有者和使用者同时实现:
1.APIs的拥有者通过实现特定的许可类,并在该类上调用demand()方法来确保其安全性.
2.每一个API的使用者,必须通过调用许可类上的Asset()方法来获取调用危险APIs的许可.
上面的两步必须搞定,否则Application不会run的.
需要注意的是,这个机制不会帮忙验证传入到APIs的数据和或者参数,这个还是应该有API的使用者来保证.这个是当然的啦,CAS肯定不会帮忙验证这个的.
API 拥有者需要做的事情:
如果写了一个有一定危险性的API做为Application类,必须考虑它的脆弱性,考虑是否解决它,然后考虑用什么技术手段解决.
如果决定采用CAS来封装有一定危险性的APIs,必须完成一下步骤,同时,需要了解CAS对APIs做了怎样的扩展以及APIs的使用者需要如何配合完成封装.
1.继承类SysCodeAccessPermission创建一个密封类来保护APIs,注意,类中的变量是将要传递给APIs的参数.
final class SysTestCodeAccessPermission extends CodeAccessPermission
{
    str _data;
}

2.重写Copy方法返回一个Permission对象,这样可以避免Permission被修改掉并传给APIs.
public CodeAccessPermission copy()
{
    
return new SysTestCodeAccessPermission(_data);
}

3.在Permission泪中写一个访问器用来访问参数.
private str data()
{
    
return _data;
}

4.为授权所需要的所有的自定义参数写构造器.
public void new(str d)
{
    super();

    _data 
= d;
}

5.重载isSubsetof()方法,比较两个Permission对象,以判定时候有权限调用APIs.如果Permission存在则返回true,否则返回false.必须设计好如何更好的实现这个方法,因为它是针对具体的API的.如果permission类没有参数,则该方法返回true.
public boolean isSubsetOf(CodeAccessPermission _target)
{
    SysTestCodeAccessPermission sysTarget 
= _target;
    
return _data == sysTarget.data();
}

6.在调用APIs的功能之前,调用Demand方法,该方法执行运行时栈遍历,以确保在同一层有用于授权的permission和前面提到的检查.
public static void dangerousApi(str data)
{
    SysTestCodeAccessPermission p 
= new SysTestCodeAccessPermission(data);
    p.demand();

    
//Do dangerous stuff here.
}

API使用者需要做的事情:
下面是两个例子:
1.在TextBuffer类上应用CAS
TextBuffer用于处理任意的文本.用于管理任意的文本内容或者创建并进行处理文本文件.TextBuffer有各种字符串处理功能,简单的记事薄和文件接口.
如下方法在服务器端通过CAS使其危险性降低
public boolean fromFile(str filename, [int encoding=FileEncoding::AUTO])
public boolean toFile(str filename, [int encoding=FileEncoding::ACP])
如果代码执行在客户端,啥代码都不用改,如果代码标记了client server则既可以运行在client,又可以运行在server,有两个选择,要么把它改成只运行在client端,要么用前面提到的方式用CAS封装.
下面的代码是在server端调用TextBuffer的示例.
server void MyServerFunction()
{
// Declare the CAS Permission object.
FileIOPermission fileIOPermission;
TextBuffer txtb 
= new TextBuffer();

// Assert that it is okay to read and write files and Clipboard
// because the content is coming from a static file name.
fileIOPermission = new FileIOPermission(filename, ‘rw’);
fileIOPermission.assert();

// From file will demand CAS permission (read)
txtb.fromFile("c:\\temp\\myfile.txt"); // Read text from file

// To clipboard will demand CAS permission (write)
txtb.toClipboard(); // Copy it to the clipboard

// To file will demand CAS permission (write)
txtb.toFile(("c:\\temp\\myfile.txt"); // Write text to file
}

2.在Dll API上应用CAS
DLL API运行X++代码直接调用Win32 DLL,两个类来实现这个功能,DLl和DLLFunction.DLL类的如下方法在server段被CAS所保护.
public void new(str filename)
用DLLFunction可以调用通过DLL类加载的DLL中的函数,如果代码调用代码可能运行在server端,必须改成如下调用方式.
server void MyServerFunction()
{
// Declare an interop permission of the right kind
InteropPermission dllPermission = 
new InteropPermission(InteropKind::DllInterop);
DLL           _DLL;
DLLFunction   _chartCreate;

// assert that it is okay to use COM in this function
dllPermission.assert();

// construct operation demands CAS permission
_DLL = new DLL('cfx2032.dll');

// Method definition is not protected by CAS
_chartCreate = new DLLFunction(_DLL,'chart_Create');
_chartCreate.returns(ExtTypes::DWord);
      _chartCreate.arg(ExtTypes::DWord,
                      ExtTypes::DWord,
                      ExtTypes::DWord,
                      ExtTypes::DWord,
                      ExtTypes::DWord);

      
// Invoke operation demands CAS permission
      _windowhdl = _chartCreate.call(…);

      
// Optionally call revertAssert() to limit scope of assert.
      CodeAccessPermission::revertAssert();
}

posted on 2006-08-09 20:01  佛西亚  阅读(814)  评论(3编辑  收藏  举报