[AX]AX2012 code access permission

假设你是个共用库API开发人员,你开发的API函数交由他人使用,你的一些API函数会在AOS上做一些危险的动作,比如修改一些服务器端的文件、调用WIN32函数,如果你的API被一些恶意代码利用,而不采取措施的话可能就造成了安全的漏洞,对此AX2012引入CodeAccessPermission(http://msdn.microsoft.com/EN-US/library/aa625357.aspx)检查权限。这不是AX2012才有的概念,早版本的AX已经支持,如何来保护我们的API防止被利用呢?来看看微软文档“Writing secure X++ code”(http://www.microsoft.com/en-us/download/details.aspx?id=21248)的一个例子(有所修改)。

首先需要从CodeAccessPermission扩展一个自己的代码安全类: 

final class SysTestCodeAccessPermission extends CodeAccessPermission
{
    container _data;
}
public void new(container d)
{
    ;
    super();
    _data=d;
}
private container data()
{
    return _data;
}
public CodeAccessPermission copy()
{
    return new SysTestCodeAccessPermission(_data);
}
public boolean isSubsetOf(CodeAccessPermission _target)
{
    SysTestCodeAccessPermission sysTarget = _target;
    int i;
    boolean ret=true;
    ;
    
    //Check if the required permission in the given permission set
    for(i=1;i<=conLen(_data);i++)
    {
        if(!conFind(sysTarget.data(),conPeek(_data,i)))
        {
            ret=false;
            break;
        }
    }
    return ret;
}

在API函数中需要“Demand”运行代码所需要的权限,比如下面的dangerousRead需要“Read”权限,dangerousWrite需要“Write”权限:

class MyAPIClass
{
}
public static void dangerousRead(str data)
{
    container c;
    SysTestCodeAccessPermission p;
    ;
    c=conIns(c,1,"Read");
    p= new SysTestCodeAccessPermission(c);
    p.demand();

    //Do dangerous stuff here.
    info("Read:" + data);
}
public static void dangerousWrite(str data)
{
    container c;
    SysTestCodeAccessPermission p;
    ;
    c=conIns(c,1,"Write");
    p= new SysTestCodeAccessPermission(c);
    p.demand();

    //Do dangerous stuff here.
    info("Write:" + data);
}

在使用我们API的代码中,则要断言“assert”调用程序可用的权限:

class TestMyAPIClass
{
}
public server static void main(Args args)
{
    str data="Test string";
    SysTestCodeAccessPermission permission;
    container c;
    ;
    c=conIns(c,1,"Read");
    c=conIns(c,1,"Write");
    permission=new SysTestCodeAccessPermission(c);
    permission.assert();

    //Read API
    MyAPIClass::dangerousRead(data);

    //Write API
    MyAPIClass::dangerousWrite(data);
}

如果注释掉“permission.assert()”或者“c=conIns(c,1,"Read");”、“c=conIns(c,1,"Write");”中的任何一行,我们都会得到类似“Request for the permission of type 'SysTestCodeAccessPermission' failed.”这样的异常。

说实话,单就这个例子我们是看不出来有什么用,对于API的编写者无非是多了个permission.demand及在isSubsetOf中比较下权限,而对于API的使用者permission.assert一下就可用了。AX包含一些自带从CodeAccessPermission扩展的类,比如FileIOPermission、RunAsPermission大体上都只是在调用相应的危险代码前断言就行了。真的是这么简单吗?事实远比看到的复杂,在MSDN上找不到更多有用的说明,幸运的是我们知道.net也有code access security机制,在System.Security命名空间有个相同名称的CodeAccessPermission 类,这个.NET的类也有demand、Assert等方法,这是巧合吗?肯定不是,虽然不确定AX的code access security是不是在.NET的code access security基础上构建的,但可以推断两者的用途及原理应该差不多,理解了.net的CAS,也就容易理解AX的CAS了。如前所说,要搞懂.net的CAS也还真不容易,MSDN上很多概念都很抽象,还是给大家推荐一篇对此觉得很经典的文章吧(http://www.codeproject.com/Articles/5724/Understanding-NET-Code-Access-Security)。

如果仔细阅读了上面的文章,回到这里简单总结一下:.net CAS是CLR的一种安全机制,使用各种各样的permission来保护危险代码防止非法调用,要授予使用的哪些permission是通过.net configuration tool来定义安全策略,在调用危险代码前可以使用C#的特性来明确定义危险代码所要求的权限,或者是在代码中动态的调用CodeAccessPermission或其扩展类的Demand()方法,它会在当前调用堆栈中从下到上逐级合并检查计算相应的权限集,我们能知道的是这是一个复杂的权限计算过程,如果结果权限集没有代码要求的权限,自然就是报错了。那Assert的作用呢,就是在做堆栈从下到上权限检查的时候,如果碰到Assert,就会使用Assert所明确的权限,而不再继续向堆栈上一级搜索计算权限。AX CodeAccessPermission的demand该和.NET差不多,它们作用类似,上面的代码就不难理解了。

剩下的问题是如果我们可以随意断言(Assert),岂不是可以任意指定调用代码的权限?答案当然是否定的,在.NET平台,可以调用Assert的代码必须有SecurityPermission的Assertion权限(SecurityPermission设置Assertion Flag),这个自然是通过由.net runtime security policy通过configuration tool配置的。那么AX中调用CodeAccessPermission.assert()又是哪里来设置的呢?只能猜测同样也是.NET平台的安全策略,有知道的读者还望不吝赐教。

原文地址:https://www.cnblogs.com/duanshuiliu/p/2696936.html