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的参数.
下面是两个例子:
1.在TextBuffer类上应用CAS
TextBuffer用于处理任意的文本.用于管理任意的文本内容或者创建并进行处理文本文件.TextBuffer有各种字符串处理功能,简单的记事薄和文件接口.
如下方法在服务器端通过CAS使其危险性降低
下面的代码是在server端调用TextBuffer的示例.
DLL API运行X++代码直接调用Win32 DLL,两个类来实现这个功能,DLl和DLLFunction.DLL类的如下方法在server段被CAS所保护.
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.{
str _data;
}
public CodeAccessPermission copy()
{
return new SysTestCodeAccessPermission(_data);
}
3.在Permission泪中写一个访问器用来访问参数.{
return new SysTestCodeAccessPermission(_data);
}
private str data()
{
return _data;
}
4.为授权所需要的所有的自定义参数写构造器.{
return _data;
}
public void new(str d)
{
super();
_data = d;
}
5.重载isSubsetof()方法,比较两个Permission对象,以判定时候有权限调用APIs.如果Permission存在则返回true,否则返回false.必须设计好如何更好的实现这个方法,因为它是针对具体的API的.如果permission类没有参数,则该方法返回true.{
super();
_data = d;
}
public boolean isSubsetOf(CodeAccessPermission _target)
{
SysTestCodeAccessPermission sysTarget = _target;
return _data == sysTarget.data();
}
6.在调用APIs的功能之前,调用Demand方法,该方法执行运行时栈遍历,以确保在同一层有用于授权的permission和前面提到的检查.{
SysTestCodeAccessPermission sysTarget = _target;
return _data == sysTarget.data();
}
public static void dangerousApi(str data)
{
SysTestCodeAccessPermission p = new SysTestCodeAccessPermission(data);
p.demand();
//Do dangerous stuff here.
}
API使用者需要做的事情:{
SysTestCodeAccessPermission p = new SysTestCodeAccessPermission(data);
p.demand();
//Do dangerous stuff here.
}
下面是两个例子:
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封装.public boolean toFile(str filename, [int encoding=FileEncoding::ACP])
下面的代码是在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{
// 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
}
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();
}
{
// 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();
}