• ballerina 学习 三十二 编写安全的程序


    ballerina编译器已经集成了部分安全检测,在编译时可以帮助我们生成错误提示,同时ballerina 标准库
    已经对于常见漏洞高发的地方做了很好的处理,当我们编写了有安全隐患的代码,编译器就已经提示给
    我们了。
    常见的问题

    • sql 注入
    • path 操作
    • file 操作
    • 未授权文件访问
    • 为校验的重定向

    确保ballerina 标准库的安全

    ballerina 标准库对于安全敏感的函数以及操作使用@sensitive 注解进行说明,可以确保容易出现漏洞的数据传递
    给参数
    比如,ballerina 标准库的select

    public native function select(@sensitive string sqlQuery, typedesc? recordType,
                                  boolean loadToMemory = false, Param... parameters)
                                 returns @tainted table|error;

    安全的使用不可信数据

    实际中我们肯定会碰到需要传递非可信数据,我们可以使用 untaint 表达式进行处理,同时对于返回值我们可以使用
    @untainted 注解
    参考

    boolean isValid = isNumeric(studentId);
    if (isValid) {
       var dt = testDB->select("SELECT NAME FROM STUDENT WHERE ID = " +
                               untaint studentId, ResultStudent);
    }
    
    function sanitizeSortColumn (string columnName) returns @untainted string {
       string sanitizedSortColumn = columnName;
       // Sanitize logic to make sure return value is safe
       return sanitizedSortColumn;
    }
    

    保护密码以及secret key

    ballerina 提供了api 可以访问不同源的配置信息,对于配置文件中包含密码信息的必须加密
    处理,框架提供了工具可以对于配置进行加密

    ballerina encrypt
    按照提示输入需要加密的名称,会生成一个加密key,我们可以使用配置文件,或者环境变量获取。
    默认会找一个secret.txt的文件,里面存储了加密密钥,请求之后会自动删除,对于没有这个文件的
    会提示输入密钥

    认证&&授权

    ballerina 的 http 服务可以配置的方式增强认证以及授权,ballerina 支持jwt 以及basic 模式的认证,
    使用basic模式时,用户信息可以通过配置文件加载,同时推荐使用https 方式进行数据访问,增强
    安全性

    • jwt 认证
      可以通过http:AuthProvider 进行配置
      参考
    import ballerina/http;
    
    http:AuthProvider jwtAuthProvider = {
       scheme:"jwt",
       issuer:"ballerina",
       audience: "ballerina.io",
       clockSkew:10,
       certificateAlias: "ballerina",
       trustStore: {
           path: "${ballerina.home}/bre/security/ballerinaTruststore.p12",
           password: "ballerina"
       }
    };
    
    endpoint http:SecureListener secureHelloWorldEp {
       port:9091,
       authProviders:[jwtAuthProvider],
       secureSocket: {
           keyStore: {
               path: "${ballerina.home}/bre/security/ballerinaKeystore.p12",
               password: "ballerina"
           }
       }
    };
    
    @http:ServiceConfig {
       basePath:"/hello"
    }
    service<http:Service> helloWorld bind secureHelloWorldEp {
    
       @http:ResourceConfig {
           methods:["GET"],
           path:"/"
       }
       sayHello (endpoint caller, http:Request req) {
           http:Response resp = new;
           resp.setTextPayload("Hello, World!");
           _ = caller->respond(resp);
       }
    }
    • http basic 认证
      参考代码
    import ballerina/http;
    
    http:AuthProvider basicAuthProvider = {
       scheme:"basic",
       authStoreProvider:"config"
    };
    
    endpoint http:SecureListener secureHelloWorldEp {
       port:9091,
       authProviders:[basicAuthProvider],
       secureSocket: {
           keyStore: {
               path: "${ballerina.home}/bre/security/ballerinaKeystore.p12",
               password: "ballerina"
           }
       }
    };
    
    @http:ServiceConfig {
       basePath:"/hello",
       authConfig:{
          scopes:["hello"]
       }
    }
    service<http:Service> helloWorld bind secureHelloWorldEp {
    
       @http:ResourceConfig {
           methods:["GET"],
           path:"/"
       }
       sayHello (endpoint caller, http:Request req) {
           http:Response resp = new;
           resp.setTextPayload("Hello, World!");
           _ = caller->respond(resp);
       }
    }

    用户账户配置信息(通过配置文件)

    sample-users.toml
    
    ["b7a.users"]
    
    ["b7a.users.generalUser"]
    password="@encrypted:{pIQrB9YfCQK1eIWH5d6UaZXA3zr+60JxSBcpa2PY7a8=}"
    
    ["b7a.users.admin"]
    password="@encrypted:{pIQrB9YfCQK1eIWH5d6UaZXA3zr+60JxSBcpa2PY7a8=}"
    scopes="hello"

    加载配置

    ballerina run --config sample-users.toml basic_auth_sample.bal
    • 说明
      在认证服务的同时,我们可以配置scope,指定权限范围,还是比较方便的

    下游服务的认证

    实际上就是在client 端加载认证信息,方便调用

    • 一个jwt client 的例子
    import ballerina/http;
    
    http:AuthProvider jwtAuthProvider = {
       scheme:"jwt",
       propagateToken: true,
       issuer:"ballerina",
       audience: "ballerina.io",
       clockSkew:10,
       certificateAlias: "ballerina",
       trustStore: {
           path: "${ballerina.home}/bre/security/ballerinaTruststore.p12",
           password: "ballerina"
       }
    };
    
    endpoint http:SecureListener secureHelloWorldEp {
       port:9091,
       authProviders:[jwtAuthProvider],
       secureSocket: {
           keyStore: {
               path: "${ballerina.home}/bre/security/ballerinaKeystore.p12",
               password: "ballerina"
           }
       }
    };
    
    endpoint http:Client downstreamServiceEP {
       url: "https://localhost:9092",
       auth: { scheme: http:JWT_AUTH },
       secureSocket: {
           trustStore: {
               path: "${ballerina.home}/bre/security/ballerinaTruststore.p12",
               password: "ballerina"
           }
       }
    };
    
    @http:ServiceConfig {
       basePath:"/hello",
       authConfig:{
          scopes:["hello"]
       }
    }
    service<http:Service> helloWorld bind secureHelloWorldEp {
    
       @http:ResourceConfig {
           methods:["GET"],
           path:"/"
       }
       sayHello (endpoint caller, http:Request req) {
           http:Response response = check downstreamServiceEP->get("/update-stats",
                                                             message = untaint req);
           _ = caller->respond(response);
       }
    }
    
    // ----------------------------------------------
    // Following code creates the downstream service
    // ----------------------------------------------
    
    http:AuthProvider downstreamJwtAuthProvider = {
       scheme:"jwt",
       issuer:"ballerina",
       audience: "ballerina.io",
       clockSkew:10,
       certificateAlias: "ballerina",
       trustStore: {
           path: "${ballerina.home}/bre/security/ballerinaTruststore.p12",
           password: "ballerina"
       }
    };
    
    endpoint http:SecureListener secureUpdateServiceEp {
       port:9092,
       authProviders:[downstreamJwtAuthProvider],
       secureSocket: {
           keyStore: {
               path: "${ballerina.home}/bre/security/ballerinaKeystore.p12",
               password: "ballerina"
           }
       }
    };
    
    @http:ServiceConfig {
       basePath:"/update-stats"
    }
    service<http:Service> updateService bind secureUpdateServiceEp {
    
       @http:ResourceConfig {
           methods:["GET"],
           path:"/"
       }
       updateStats (endpoint caller, http:Request req) {
           http:Response resp = new;
           resp.setTextPayload("Downstream Service Received JWT: " +
                               untaint req.getHeader("Authorization"));
           _ = caller->respond(resp);
       }
    }

    说明

    ballerina 的设计以及功能还是很方便的,功能很齐全。

    参考资料

    https://ballerina.io/learn/how-to-write-secure-ballerina-code/

  • 相关阅读:
    Android Activity中获取当前焦点的控件,自动化输入EditText
    Java Android 二进制文件读写
    Delphi 动态数组、静态数组、TBytes 的区别
    IIS日志分析工具-Log Parser
    信息安全等级保护三级系统基线要求判分标准之应用安全
    通过TCPView工具查看foxmail用exchange方式连接exchange时用什么端口
    Windows2008R2操作系统日志清理
    批量IP自动netcat脚本
    批量IP自动ping脚本
    批量移动AD用户到指定OU
  • 原文地址:https://www.cnblogs.com/rongfengliang/p/9933839.html
Copyright © 2020-2023  润新知