马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
鸿蒙双向认证
开发环境 基于API12
参考文档
切换到鸿蒙也要用上双向认证。利用的其中的 rcp 功能,详细文档https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/remote-communication-rcp-V5
双向认证包含两个方向,分为客户端验证服务端的证书和服务端验证客户端的证书。
客户端验证服务端的证书
这个就必要把服务端的证书内置在客户端里边,并且在请求的时候获取到服务端的证书,然后自己进行对比证书是否同内置的一样。
服务器证书的校验等级有以下几种:
- DefaultTrustEvaluator,利用默认的验证方式,验证证书的有效性,证书信任链那套
- RevocationTrustEvaluator,验证证书是否被吊销
- PinnedCertificatesTrustEvaluator,验证证书是否同当地的同等,可以是自签证书
- PublicKeysTrustEvaluator,验证证书的公钥,可以是自签证书,不过这个有个好处就是不消关心证书的有效期了
- CompositeTrustEvaluator,混合模式
- DisabledTrustEvaluator,不验证证书
可以按需自己处理。本文以对比公钥为例。
首先获取当地证书及证书的公钥。
- let context = getContext(this)
- const getRawFileContent = (ctx: Context, file: string) : string => {
- let buffer = ctx.resourceManager.getRawFileContentSync(file).buffer
- return String.fromCharCode(...new Uint8Array(buffer))
- }
- function stringToUint8Array(str: string): Uint8Array {
- let arr: Array<number> = [];
- for (let i = 0, j = str.length; i < j; i++) {
- arr.push(str.charCodeAt(i));
- }
- return new Uint8Array(arr);
- }
- const uInt8ToString = (buffer: Uint8Array): string => {
- return String.fromCharCode(...new Uint8Array(buffer))
- }
- let serverCert: cert.X509Cert | null = null
- let serverCertStr: string | null = null
- cert.createX509Cert({
- data: stringToUint8Array(getRawFileContent(context, 'server.cer')),
- encodingFormat: cert.EncodingFormat.FORMAT_DER
- }).then(x509Cert => {
- serverCert = x509Cert
- serverCertStr = uInt8ToString(serverCert?.getPublicKey().getEncoded().data)
- }).catch((error: BusinessError) => {
- })
复制代码 增长自定义验证证书函数。对比公钥是否同等。
- {
- security: {
- remoteValidation: (context: rcp.ValidationContext) => {
- let tar = uInt8ToString(context.x509Certs[0].getPublicKey().getEncoded().data)
- if (serverCertStr === tar) {
- return true
- }
- return false
- },
- },
- }
复制代码 如许客户端就验证了服务端证书是否符合要求。
服务端验证客户端的证书
由于接口请求的题目,必要把客户端证誊写入到沙盒里边,然后把沙盒地点传进去,就有点贫苦。
首先写入客户端证书到沙盒。
本文必要利用到crt及key两个文件。接口crt文件必要文本形式,但是key又必要沙盒地点。
- const getRawFileContent = (ctx: Context, file: string) : string => {
- let buffer = ctx.resourceManager.getRawFileContentSync(file).buffer
- return String.fromCharCode(...new Uint8Array(buffer))
- }
- let context = getContext(this)
- let filesDir = context.filesDir
- function saveFile(fn: string) {
- let file = fs.openSync(filesDir + '/' + fn, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
- let clientContent = context.resourceManager.getRawFileContentSync(fn)
- fs.writeSync(file.fd, clientContent.buffer)
- fs.fsyncSync(file.fd)
- fs.closeSync(file)
- }
- saveFile('client.key')
复制代码 然后提供客户端证书给服务端进行校验。
- {
- security: {
- certificate: {
- content: getRawFileContent(context, 'client.crt'),
- key: filesDir + '/client.key',
- type: 'PEM',
- keyPassword: 'xxx'
- },
- },
- }
复制代码 如许就能把证书提供给服务端进行校验了。
完整实例
- import { BusinessError } from '@ohos.base';import { rcp } from "@kit.RemoteCommunicationKit";import fs from '@ohos.file.fs';import { cert } from '@kit.DeviceCertificateKit';import { cryptoFramework } from '@kit.CryptoArchitectureKit';const getRawFileContent = (ctx: Context, file: string) : string => {
- let buffer = ctx.resourceManager.getRawFileContentSync(file).buffer
- return String.fromCharCode(...new Uint8Array(buffer))
- }
- let context = getContext(this)
- let filesDir = context.filesDir
- function saveFile(fn: string) {
- let file = fs.openSync(filesDir + '/' + fn, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
- let clientContent = context.resourceManager.getRawFileContentSync(fn)
- fs.writeSync(file.fd, clientContent.buffer)
- fs.fsyncSync(file.fd)
- fs.closeSync(file)
- }
- saveFile('client.key')
- function stringToUint8Array(str: string): Uint8Array { let arr: Array<number> = []; for (let i = 0, j = str.length; i < j; i++) { arr.push(str.charCodeAt(i)); } return new Uint8Array(arr);}const uInt8ToString = (buffer: Uint8Array): string => { return String.fromCharCode(...new Uint8Array(buffer))}let serverCert: cert.X509Cert | null = nulllet serverCertStr: string | null = nullcert.createX509Cert({ data: stringToUint8Array(getRawFileContent(context, 'server.cer')), encodingFormat: cert.EncodingFormat.FORMAT_DER}).then(x509Cert => { serverCert = x509Cert serverCertStr = uInt8ToString(serverCert?.getPublicKey().getEncoded().data)}).catch((error: BusinessError) => { console.error('createX509Cert failed, errCode: ' + error.code + ', errMsg: ' + error.message);})const defaultTimeout: number = 60*1000const createRequestConfiguration = (timeout: number): rcp.Configuration => { return { security: { remoteValidation: (context: rcp.ValidationContext) => { let tar = uInt8ToString(context.x509Certs[0].getPublicKey().getEncoded().data) if (serverCertStr === tar) { return true } return false }, certificate: { content: getRawFileContent(context, 'client.crt'), key: filesDir + '/client.key', type: 'PEM', keyPassword: 'xxx' }, }, transfer: { autoRedirect: true, timeout: { connectMs: 5000, transferMs: timeout, } } }}const sessionConfig: rcp.SessionConfiguration = { requestConfiguration: createRequestConfiguration(defaultTimeout)}const session: rcp.Session = rcp.createSession(sessionConfig)export const rcpget = (url:string, timeout: number = defaultTimeout):Promise<object> => { return new Promise((resolve, reject) => { let request = new rcp.Request(url, 'GET', getHeaders()) if (timeout != defaultTimeout) { request.configuration = createRequestConfiguration(timeout) } session.fetch(request).then((response:rcp.Response) => { if (response.statusCode == 200) { resolve(data) } else { reject() } }).catch((err: BusinessError) => { reject() }) })}export const rcppost = (url: string, params: Record<string, string | number>, timeout: number = defaultTimeout):Promise<object> => { let p: string[] = [] for(let kv of Object.entries(params)) { p.push(`${kv[0]}=${kv[1]}`) } let pstr: string = p.join('&') return new Promise((resolve, reject) => { let request: rcp.Request if (pstr == '') { request = new rcp.Request(url, 'POST', getHeaders()) } else { request = new rcp.Request(url, 'POST', getHeaders(), pstr) } if (timeout != defaultTimeout) { request.configuration = createRequestConfiguration(timeout) } session.fetch(request).then((response:rcp.Response) => { if (response.statusCode == 200) { resolve(data) } else { reject() } }).catch((err: BusinessError) => { reject() }) })}
复制代码 如此这般就能实现双向认证。感觉安全级别又上了一个等级。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |