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/

原文地址:https://www.cnblogs.com/rongfengliang/p/9933839.html