Open Charge Point Protocol JSON 1.6
OCPP-J 1.6 规范
目录
- 引言
1.1. 本文档的目的
1.2. 目标受众
1.3. OCPP-S 和OCPP-J
1.4. 约定
1.5. 定义与缩写
1.6. 参考文献
- 优点与问题
- 连接
3.1. 客户端请求
3.2. 服务器响应
3.3. 更多信息
- RPC 框架 ........................................................................................................................ 9
4.1. 引言
4.2. 不同消息类型的消息结构................................................................................................11
- 连接 ..................................................................................................................................... 14
5.1. 压缩..................................................................................................................................14
5.2. 数据完整性........................................................................................................................14
5.3. WebSocket Ping 与 OCPP 心跳的关系.................................................................................14
5.4. 重新连接..............................................................................................................................15
5.5. 网络节点层次结构..........................................................................................................15
- 安全性 ................................................................................................................................. 15
6.1. 网络级别的安全性..........................................................................................................15
6.2. 通过 TLS 的 OCPP-J.........................................................................................................15
7.配置 .............................................................................................................................20
文档版本 | 1.6 |
文档状态 | 最终版 |
文档发布日期 | 2015-10-08 |
版权所有 © 2010 – 2015 Open Charge Alliance。保留所有权利。
本文档在Creative CommonsAttribution-NoDerivatives 4.0 国际公共许可证(CC BY-ND 4.0 Legal Code | Attribution-NoDerivs 4.0 International | Creative Commons)下提供。
版本历史
版本 | 日期 | 作者 | 描述 |
1.6 | 2015-10-08 | Patrick Rademakers Reinier Lamers Robert de Leeuw | 更新至1.6 Asciidoc格式调整,移除 1.5版本的JSON模式 一些澄清说明 添加了1.5版本的JSON模式 |
内容目录
1. 引言
1.1. 本文档的目的
本文档的目的是为读者提供创建正确且可互操作的OCPP JSON实现(OCPP-J)所需的信息。我们将基于我们自己的经验,解释哪些是必须遵循的,哪些被认为是好的做法,以及哪些是不应该做的。尽管无可避免地会存在一些误解或模糊之处,但我们希望通过本文档尽可能多地防止这些问题。
1.2. 目标受众
本文档面向希望以正确且可互操作的方式理解和/或实现OCPP JSON的开发者。假定读者具备在服务器或嵌入式设备上实现Web服务的基础知识。
1.3. OCPP-S和OCPP-J
随着OCPP 1.6的引入,OCPP有了两种不同的风格;除了基于SOAP的实现外,还有使用更加紧凑的JSON替代方案的可能性。为了避免在通信中混淆实现类型,我们建议使用不同的后缀-J和-S来指示JSON或SOAP。在一般术语中,这将是OCPP-J表示JSON,OCPP-S表示SOAP。特定版本的术语将是OCPP1.6J或OCPP1.2S。如果未为OCPP 1.2或1.5指定后缀,则必须假定为SOAP实现。从1.6版本发布开始,这不能再是隐含的,而应该始终明确说明。如果一个系统同时支持JSON和SOAP变体,那么将其标记为OCPP1.6JS而不是仅标记为OCPP1.6被认为是好的做法。
本文档描述了OCPP-J,有关OCPP-S的信息,请参阅:[OCPP_IMP_S]
1.4. 约定
本文档中的关键词“MUST”、“MUSTNOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY”和“OPTIONAL”应如[RFC2119]所述进行解释。
1.5. 定义与缩写
IANA | Internet 编号分配机构(Internet Assigned Numbers Authority)。 |
OCPP-J | 使用JSON通过WebSocket进行OCPP通信。 特定的OCPP版本应该使用J扩展来表示。OCPP1.5J意味着我们正在讨论的是1.5版本的JSON/WebSocket实现。 |
OCPP-S | OCPP通过SOAP和HTTP(S)进行通信。从版本1.6开始,这应该明确提及。除非明确指定其他方式,否则旧版本默认使用S,例如OCPP1.5等同于OCPP1.5S。 |
RPC | 远程过程调用(Remote Procedure Call,简称RPC) |
WAMP | WAMP 是一个开放的 WebSocket 子协议,它提供消息模式来处理异步数据。 |
1.6. 参考文献
[JSON] | |
[OCPP_IMP_S] | OCPP SOAP 实现规范 |
[RFC2119] | "RFC中用于指示要求级别的关键词"。S. Bradner。1997年3月。 |
[RFC2616] | "超文本传输协议 — HTTP/1.1"。 |
[RFC2617] | "HTTP 认证:基本认证和摘要认证"。RFC 2617 - HTTP Authentication: Basic and Digest Access Authentication |
[RFC3629] | "UTF-8,ISO 10646的一种转换格式"。RFC 3629 - UTF-8, a transformation format of ISO 10646 |
[RFC3986] | “统一资源标识符(URI):通用语法”。RFC 3986 - Uniform Resource Identifier (URI): Generic Syntax |
[RFC5246] | “传输层安全性(TLS)协议;版本1.2”。RFC 5246 - The Transport Layer Security (TLS) Protocol Version 1.2 |
[RFC6455] | "WebSocket 协议"。RFC 6455 - The WebSocket Protocol |
[WAMP] | |
[WIKIWS] | |
[WS] |
- 优点与问题 WebSocket协议在[RFC6455]中定义。尽管存在早期草案WebSocket规范的可用实现,但OCPP-J实现应该使用[RFC6455]中描述的协议。请注意,WebSocket在TCP之上定义了自己的消息结构。在TCP级别上,通过WebSocket发送的数据会被封装在带有头部的WebSocket帧中。当使用框架时,这完全是透明的。然而,在为嵌入式系统工作时,可能无法使用WebSocket库,那么就需要根据[RFC6455]自己正确地封装消息。
- 连接 在使用OCPP-J的充电点和中央系统之间的连接中,中央系统作为WebSocket服务器,而充电点作为WebSocket客户端。
3.1. 客户端请求为了建立连接,充电点按照[RFC6455]的第4节“开启握手”所述发起WebSocket连接。OCPP-J对URL和WebSocket子协议施加了额外的限制,具体细节将在以下两节4.1.1和4.1.2中详细说明。
3.1.1. 连接URL为了发起WebSocket连接,充电点需要一个URL([RFC3986])来连接到。这个URL被称为“连接URL”。这个连接URL是特定于一个充电点的。充电点的连接URL包含充电点身份,以便中央系统知道哪个WebSocket连接属于哪个充电点。
支持OCPP-J的中央系统必须至少提供一个OCPP-J端点URL,充电点应该从这个URL推导出其连接URL。这个OCPP-J端点URL可以是任何带有“ws”或“wss”方案的URL。充电点如何获取OCPP-J端点URL不在本文档的讨论范围内。
为了推导出其连接URL,充电点通过向OCPP-J端点URL的路径部分添加一个“/”(U+002FSOLIDUS)和一个唯一标识充电点的字符串来修改它。这个唯一标识字符串必须根据需要进行百分比编码,如[RFC3986]所述。
示例1:对于身份为“CP001”的充电点,连接到具有OCPP-J端点URL"ws://centralsystem.example.com/ocpp"的中央系统,这将给出以下连接URL:ws://centralsystem.example.com/ocpp/CP001
示例2:对于身份为“RDAM 123”的充电点,连接到具有OCPP-J端点URL"wss://centralsystem.example.com/ocppj"的中央系统,这将给出以下URL:wss://centralsystem.example.com/ocppj/RDAM%20123
3.1.2. OCPP版本Sec-Websocket-Protocol字段中必须指定确切的OCPP版本。这应当是以下值之一:
表1: OCPP版本
OCPP版本 | WebSocket子协议名称 |
1.2 | ocpp1.2 |
1.5 | ocpp1.5 |
1.6 | ocpp1.6 |
2.0 | Ocpp2.0 |
对于OCPP 1.2、1.5和2.0的版本,它们是官方的WebSocket子协议名称值。这些值已在IANA进行了注册。
请注意,列表中包含了OCPP 1.2和1.5。由于WebSocket上的JSON解决方案与实际的消息内容无关,因此该解决方案也可以用于较旧的OCPP版本。请牢记,在这些情况下,实施最好也保持对基于SOAP的解决方案的支持以实现互操作性。
将OCPP版本作为OCPP-J端点URL字符串的一部分被认为是良好的做法。但是,如果你运行的是一个可以在同一OCPP-J端点URL上处理多个协议版本的网络服务,那么这不是必需的。
3.1.3. 打开HTTP请求示例以下是一个OCPP-J连接握手时打开HTTP请求的示例:
复制代码
GET /webServices/ocpp/CP3211 HTTP/1.1 | |
Host: some.server.com:33033 | |
Upgrade: websocket | |
Connection: Upgrade | |
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== | |
Sec-WebSocket-Protocol: ocpp1.6, ocpp1.5 | |
Sec-WebSocket-Version: 13 |
粗体部分在每个WebSocket握手请求中都会找到,而其他部分则特定于本示例。
在此示例中,中央系统的OCPP-J端点URL是 "ws://some.server.com:33033/webServices/ocpp"。充电点的唯一标识符是 "CP3211",因此请求的路径变为"webServices/ocpp/CP3211"。
通过Sec-WebSocket-Protocol头部,充电点表示它可以使用OCPP1.6J和OCPP1.5J,并优先使用前者。
此示例中的其他头部是HTTP和WebSocket协议的一部分,对于在第三方WebSocket库之上实现OCPP-J的开发者来说并不相关。这些头部的作用在[RFC2616]和[RFC6455]中有解释。
3.2. 服务器响应
在接收到充电点的请求后,中央系统必须按照[RFC6455]中描述的方式通过响应完成握手。
以下是与OCPP-J相关的特定条件:
• 如果中央系统在URL路径中不识别充电点标识符,它应该发送一个带有状态码404的HTTP响应,并按照[RFC6455]中的描述终止WebSocket连接。
• 如果中央系统不同意使用客户端提供的子协议之一,它必须完成WebSocket握手,但响应中不包含Sec-WebSocket-Protocol头部,然后立即关闭WebSocket连接。
因此,如果中央系统接受上述示例请求并同意与充电点使用OCPP 1.6J,中央系统的响应将如下所示:
HTTP/1.1101 Switching Protocols
Upgrade:websocket
Connection:Upgrade
Sec-WebSocket-Accept:s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol:ocpp1.6
粗体部分在每个WebSocket握手响应中都是这样出现的,其他部分是这个示例特有的。
Sec-WebSocket-Accept头部的角色在[RFC6455]中有解释。
Sec-WebSocket-Protocol头部表示服务器将在此连接上使用OCPP1.6J。
3.3. 更多信息
对于那些自行实现WebSocket握手的人来说,[WS]和[WIKIWS]提供了更多关于WebSocket协议的信息。
- RPC框架
4.1. 引言
WebSocket是一个全双工连接,简单来说,它是一个管道,数据可以流入也可以流出,而且流入和流出之间没有明确的关系。WebSocket协议本身没有提供一种方式来将消息关联为请求和响应。为了编码这些请求/响应关系,我们需要在WebSocket之上添加一个小的协议。这个问题在WebSocket的更多用例中都会出现,因此有现成的方案来解决它。最广泛使用的是WAMP(参见[WAMP]),但使用该框架的当前版本对称处理RPC并不符合WAMP规范。由于所需的框架非常简单,我们决定定义自己的框架,受到WAMP的启发,去掉我们不需要的部分,并添加我们觉得缺失的部分。
基本上我们所需要的很简单:我们需要发送一个消息(CALL)并接收一个回复(CALLRESULT)或解释为什么消息无法正确处理(CALLERROR)。为了将来可能的兼容性,我们将保持这些消息的编号与WAMP同步。我们的实际OCPP消息将被放入一个包装器中,该包装器至少包含消息类型、唯一的消息ID和有效载荷(即OCPP消息本身)。
4.1.1. 同步性
充电点或中央系统不应该向另一方发送CALL消息,除非它之前发送的所有CALL消息都已经得到响应或已超时。当接收到带有与CALL消息相同消息ID的CALLERROR或CALLRESULT消息时,即表示该CALL消息已得到响应。
当以下情况发生时,CALL消息已超时:
• 它没有得到响应,并且• 自发送消息以来,已经过了一个与实现相关的超时间隔。
实现可以自由选择这个超时间隔。建议它们考虑到与另一方通信时所使用的网络类型。移动网络通常在最坏情况下的往返时间比固定线路长得多。
注意
上述要求不排除充电点或中央系统在等待CALLERROR或CALLRESULT时收到来自另一方的CALL消息。这种情况很难防止,因为双方的CALL消息总是可能相互交叉。
4.1.2. 字符编码
由包装器和有效载荷组成的整个消息必须使用UTF-8字符编码(参见[RFC3629])进行有效的JSON编码。
请注意,所有有效的US-ASCII文本也是有效的UTF-8,所以如果系统仅发送US-ASCII文本,它发送的所有消息都符合UTF-8要求。充电点或中央系统应该仅在发送自然语言文本时使用非US-ASCII字符。这种自然语言文本的一个例子是OCPP 2.0中LocalizedText类型中的文本。
4.1.3. 消息类型
为了识别消息类型,必须使用以下消息类型编号之一。
表2: 消息类型
消息类型 | 消息类型号 | 方向 |
CALL | 2 | 客户端 –> 服务器 |
CALLRESULT | 3 | 服务器 -> 客户端 |
CALLERROR | 4 | 服务器 -> 客户端 |
当服务器接收到一个不在此列表中的消息类型编号的消息时,它应忽略该消息的有效载荷。每种消息类型可能还包含其他必需的字段。
4.1.4. 消息ID
消息ID用于标识一个请求。一个CALL消息的消息ID必须与同一WebSocket连接上同一发送者之前用于CALL消息的所有消息ID不同。CALLRESULT或CALLERROR消息的消息ID必须与它们所响应的CALL消息的消息ID相同。
表3: 唯一的消息ID
名称 | 数据类型 | 约束 |
messageId | 字符串 | 最大长度为36个字符,以支持GUID(全局唯一标识符) |
4.2. 不同消息类型的消息结构
注意
您可能会发现在下面的段落中缺少充电点标识。这个标识在WebSocket连接握手期间进行交换,并且是连接的一个属性。每个消息都是由这个标识发送或指向这个标识的。因此,没有必要在每个消息中重复它。
4.2.1. 调用(Call)
一个调用(Call)总是由4个元素组成:标准元素MessageTypeId和UniqueId,一个特定的Action(在对方需要执行的操作),以及一个有效载荷(Payload),即该Action的参数。调用的语法如下所示:
[,"", "", {}]
表4: 调用(Call)字段
字段 | 含义 |
UniqueId | 这是一个唯一标识符,用于匹配请求和结果。 |
Action | 这是远程过程或操作的名称。这将是一个区分大小写的字符串,包含与基于SOAP的消息中的Action字段相同的值,但不包括前面的斜杠(/)。 |
Payload | 有效载荷(Payload)是一个JSON对象,包含与操作(Action)相关的参数。如果没有有效载荷,JSON允许使用两种不同的表示法:null或空对象{}。尽管这似乎微不足道,但我们认为只使用空对象表示法是一个好习惯。null通常表示未定义的东西,这与空(empty)不同,而且{}更短。 |
例如,一个BootNotification请求可能如下所示:
[2,"19223201","BootNotification",{"chargePointVendor": "VendorX", "chargePointModel":"SingleSocketCharger"}]
4.2.2. 调用结果(CallResult)
如果调用可以正确处理,结果将是一个常规的调用结果(CallResult)。由OCPP响应定义涵盖的错误情况在此上下文中不被视为错误。它们是常规结果,因此将被视为正常的调用结果(CallResult),即使结果对接收方来说不理想。
一个调用结果(CallResult)总是由3个元素组成:标准元素MessageTypeId和UniqueId,以及一个有效载荷(Payload),包含原始调用中Action的响应。调用的语法如下所示:
[,"", {}]
表5: 调用结果(CallResult)字段
字段 | 意义 |
UniqueId | 这必须是与调用请求中完全相同的ID,以便接收方能够匹配请求和结果。 |
Payload | 有效载荷是一个JSON对象,包含已执行的操作的结果。如果没有有效载荷,JSON允许使用两种不同的表示法:null或空对象{}。尽管这似乎微不足道,但我们认为只使用空对象表示法是一个好习惯。null通常表示未定义的东西,这与空(empty)不同,而且{}更短。 |
例如,一个BootNotification的响应可能如下所示:
[3,
"19223201",
{"status":"Accepted","currentTime":"2013-02-01T20:53:32.486Z","heartbeatInterval":300}
]
4.2.3. 调用错误(CallError)
我们只在以下两种情况下使用调用错误(CallError):
消息传输过程中发生错误。这可能是网络问题、服务可用性问题等。
调用已被接收,但调用的内容不符合正确消息的要求。这可能是缺少必填字段、已经有一个具有相同唯一标识符的现有调用正在处理中、唯一标识符过长等。
一个调用错误(CallError)总是由5个元素组成:标准元素MessageTypeId和UniqueId,一个errorCode字符串,一个errorDescription字符串和一个errorDetails对象。调用的语法如下所示:
[, "","", "",{}]
表6: 调用错误(CallError)字段
字段 | 含义 |
UniqueId | 这必须与调用请求中的ID完全相同,以便接收方能够匹配请求和结果。 |
ErrorCode | 这个字段必须包含下面ErrorCode表中的一个字符串。 |
ErrorDescription | 如果可能的话应该填写,否则填写一个明确的空字符串“”。 |
ErrorDetails | 这个JSON对象以未定义的方式描述错误详情。如果没有错误详情,你必须填写一个空对象{}。 |
表7: 有效的错误代码(ValidError Codes)
错误代码 | 描述 |
NotImplemented | 请求的操作接收方未知 |
NotSupported | 请求的操作被接收方识别但不支持 |
InternalError | 发生了一个内部错误,接收方无法成功处理请求的操作。 |
ProtocolError | 操作的有效载荷不完整。 |
SecurityError | 在处理操作期间发生了安全问题,导致接收方无法成功完成操作。 |
FormationViolation | 操作的有效载荷语法不正确或不符合操作的PDU结构。 |
PropertyConstraintViolation | 有效载荷的语法是正确的,但至少有一个字段包含无效的值。 |
OccurenceConstraintViolation | 操作的有效载荷语法是正确的,但至少有一个字段违反了出现约束(即该字段的值或格式不符合预定义的规则或条件)。 |
TypeConstraintViolation | 操作的有效载荷语法是正确的,但至少有一个字段违反了数据类型约束(例如,“somestring”: 12) |
GenericError | 其他未在前述中涵盖的错误 |
- 连接 5.1. 压缩 由于JSON本身非常紧凑,我们建议不要使用WebSocket [RFC6455]规范允许之外的其他任何形式的压缩。否则可能会影响互操作性。
5.2. 数据完整性对于数据完整性,我们依赖于底层的TCP/IP传输层机制。
5.3. WebSocket Ping与OCPP心跳的关系WebSocket规范定义了Ping和Pong帧,这些帧用于检查远程端点是否仍然响应。在实践中,这种机制也用于防止网络运营商在一段时间不活动后静默地关闭底层网络连接。这个WebSocket特性可以用作大多数OCPP心跳消息的替代品,但不能完全替代其所有功能。
心跳响应的一个重要方面是时间同步。Ping和Pong帧不能用于此目的,因此建议每天至少发送一条原始心跳消息,以确保充电点的时钟设置正确。
5.4. 重新连接当重新连接时,充电点不应该发送BootNotification,除非BootNotification中的一个或多个元素自上次连接以来已发生更改。对于以前的基于SOAP的解决方案,这被认为是良好的做法,但在使用WebSocket时,服务器可以在连接建立时立即根据身份和通信通道进行匹配。因此,不需要额外的消息。
5.5. 网络节点层次结构物理网络拓扑不会受到选择JSON或SOAP的影响。然而,在使用JSON的情况下,网络地址转换(NAT)的问题已经通过让充电点向中央系统打开一个TCP连接并保持此连接打开以供中央系统发起的通信来解决。因此,不再需要在中央系统和充电点之间具有能够解释和重定向SOAP调用的智能设备。
- 安全性 OCPP-J的安全性有两种方法。一种可以依赖网络级别的安全性,另一种是通过TLS使用OCPP-J。以下描述了这两种方法。 重要的是,在任何时候,都应使用这两种方法中的一种。实际上,这意味着中央系统不应该监听来自互联网的未加密的传入OCPP-J连接。
6.1. 网络级别的安全性对于安全性,可以依赖网络级别的安全性。这在历史上是通过OCPP-S实现的,在适当设置的网络上,也可以在不使用额外加密或身份验证措施的情况下使用OCPP-J。
6.2. 通过TLS的OCPP-J然而,有时在充电点和中央系统之间并没有安全网络。在这种情况下,可以使用通过TLS的OCPP-J。本节将解释如何实现这一点。
OCPP通信所需的安全性实际上由两个独立的功能组成:加密和充电点认证。
加密意味着OCPP消息被加密,以便任何未经授权的第三方都无法看到交换的消息。
充电点认证意味着中央系统可以验证充电点的身份,从而确保任何未经授权的第三方都无法伪装成充电点并向中央系统发送恶意消息。
6.2.1. 加密互联网上的加密行业标准是传输层安全性(TLS)[RFC5246]。因此,OCPP也采用该协议来加密中央系统和充电点之间的连接。TLS与WebSocket在库中得到广泛支持,对于客户端来说,使用TLS的WebSocket与使用未加密的WebSocket几乎没有什么区别。
当使用TLS时,中央系统还可以提供一个签名证书,充电点可以使用该证书来验证中央系统的身份。
由于一些充电点实现使用的是具有有限计算资源的嵌入式系统,我们对服务器端的TLS配置施加了额外的限制:
• TLS证书应为RSA证书,其大小不得超过2048字节。
6.2.2. 充电点认证对于认证,通过TLS的OCPP-J使用HTTP基本认证方案([RFC2617])。由于连接已经通过TLS加密,因此不需要对凭据进行二次加密,因此可以使用相对简单的HTTP基本认证。
当使用HTTP基本认证时,客户端(即充电点)必须在请求中提供用户名和密码。用户名等于充电点标识,它是充电点在OCPP-J连接URL中使用的识别字符串。密码是一个存储在充电点上的20字节密钥。
示例如果我们有一个充电点,其信息如下:• 充电点标识 "AL1000"• 授权密钥 0001020304050607FFFFFFFFFFFFFFFFFFFFFFFFHTTP授权头应该是:Authorization: Basic QUwxMDAwOgABAgMEBQYH
关于加密的注意事项通过HTTP基本认证进行的认证机制应仅在通过TLS加密的连接上使用。如果在未加密的连接上使用此机制,则任何能够看到充电点与中央系统之间网络流量的人都可以看到充电点凭据,从而可以冒充充电点。
设置充电点的凭据对于此充电点认证方案,充电点需要具有一个认证密钥。这个认证密钥需要以某种方式传输到充电点上。具体哪种方式好取决于充电点制造商和中央系统运营商的商业模式。
在安装期间或之前设置理想且安全的情况是,每个充电点都有自己唯一的授权密钥。如果授权密钥不是唯一的,那么一旦攻击者发现了单个充电点的授权密钥,就可以冒充运营商中央系统中的许多甚至所有充电点。
实现这一点的最简单方法是在制造或安装期间将授权密钥安装在充电点上。在这些情况下,密钥将通过OCPP之外的通信渠道在中央系统运营商和安装人员或制造商之间安全地传输。这种场景是安全的,因为密钥不是通过它要保护的通道发送的,因此监听充电点与中央系统之间连接的攻击者无法冒充充电点。
通过OCPP设置密钥
如果充电点的制造、销售和安装过程不受中央系统运营商的控制,那么就无法在每个单独的充电点上放置一个唯一的密钥,同时确保中央系统运营商知道这些密钥以及它们所属的充电点。对于这种情况,当一系列充电点离开工厂并安装时,它们最好具有相同的“主”密钥,或者通过相同的算法根据充电点标识派生出密钥。但是,如果主密钥泄露,中央系统运营商仍希望防止攻击者冒充这一系列的所有充电点。对于此用例,中央系统可以在充电点安装后通过OCPP向充电点发送一个唯一的密钥。
要通过OCPP设置充电点的授权密钥,中央系统应向充电点发送一个ChangeConfiguration.req消息,其中key为AuthorizationKey,值为20字节授权密钥的40字符十六进制表示。如果充电点对此ChangeConfiguration.req消息以带有Accepted状态的ChangeConfiguration.conf消息响应,则中央系统应假定授权密钥更改已成功,并不再接受充电点之前使用的凭据。如果充电点以带有Rejected或NotSupported状态的ChangeConfiguration.conf消息响应ChangeConfiguration.req,则中央系统应继续接受旧的凭据。尽管在这种情况下,中央系统仍应接受来自充电点的OCPP-J连接,但它可能会以不同的方式处理充电点的OCPP消息,例如不接受充电点的启动通知。
充电点在响应GetConfiguration请求时不应返回授权密钥。它可以选择完全不报告AuthorizationKey密钥,或者返回一个与实际授权密钥不相关的值。
请注意,虽然通过要保护的通道发送密钥通常被认为是不良做法,但我们认为在这里至少提供这种可能性是合适的。通常,当充电点首次在中央系统中“上线”时,会设置授权密钥。如果充电点之后产生了在上线期间设置的密钥,那么至少说明这是在上线期间连接的同一系统。虽然可能成功地将一个伪造的新充电点上线到知道所有新充电点单个“主”密钥的敌手那里,但不可能伪装成已经安装并运行的充电点。这使得一些可设想的攻击变得不可能:
• 通过伪造消息将充电点标记为占用状态来进行“预订”• 将你在公共充电点刚刚开始的会话标记为已停止,以便你不必支付那么多费用• 从已经上线的充电点发送许多伪造的交易和/或错误来干扰中央系统运营商的操作• 向中央系统发送带有他人令牌ID的伪造交易,对令牌ID的所有者造成经济损失
建议中央系统操作员将设置授权密钥作为充电点上线流程的一部分,使用OCPP 1.6中BootNotification.conf的新Pending注册状态值。新连接的充电点在其首次发送BootNotification.conf时将首先获得Pending注册状态。然后,中央系统将使用ChangeConfiguration.req为充电点设置唯一的授权密钥。只有当此ChangeConfiguration.req得到带有Accepted状态的ChangeConfiguration.conf的响应时,中央系统才会以Accepted注册状态响应启动通知。
建议中央系统操作员检查新连接充电点的异常情况。这样他可以试图检测攻击者是否设法窃取了主密钥或密钥派生算法,以及注册充电点身份的列表。例如,如果新充电点的连接速率突然增加,这可能表明存在攻击。
存储凭据
重要的是以这样的方式在充电点上存储凭据,使它们不容易丢失或重置。如果凭据丢失、被擦除或单方面更改,充电点将无法再连接到中央系统,并需要现场服务来安装新的凭据。
在中央系统方面,建议使用为密码安全存储设计的密码哈希算法,将授权密钥与唯一的盐值进行哈希存储。这确保即使包含充电点授权密钥的数据库被泄露,攻击者仍然无法以充电点的身份向中央系统进行身份验证。
6.2.3. 这些安全措施的作用及其不涉及的范围这些安全措施的范围仅限于充电点与中央系统之间的连接的身份验证和加密。它并没有解决电动汽车充电IT领域中的所有当前安全问题。
它提供了以下功能:• 充电点对中央系统的身份验证(使用HTTP基本身份验证)• 充电点与中央系统之间的连接加密• 中央系统对充电点的身份验证(使用TLS证书)
它不提供:• 保证仪表值与中央系统之间的数据未被篡改• 驾驶员的身份验证• 防止人员物理上篡改充电点
6.2.4. 对OCPP-S的适用性OCPP-J通过TLS的方法不能应用于OCPP-S。原因有两个。首先,在OCPP-S中,每次请求-响应交换都会创建一个新的TCP连接。因此,对于每次这样的请求-响应交换,都必须进行新的TLS握手,这会产生很大的带宽开销。其次,在OCPP-S中,充电点也充当服务器,因此需要一个服务器证书。追踪这么多服务器证书以及它们所属的充电点将会是一个巨大的管理负担。
- 配置 在OCPP的Get/ChangeConfiguration消息中添加了以下项目,以控制JSON/WebSockets的行为:
- 表8:额外的OCPP键
键(key) | 值(value) |
WebSocketPingInterval | 整数值A为0时,将禁用客户端WebSocket的Ping/Pong功能。在这种情况下,将不会有Ping/Pong操作,或者由服务器发起Ping,客户端用Pong进行响应。正值被解释为Ping之间的秒数。不允许使用负值。 ChangeConfiguration(配置更改)操作预期会返回一个REJECTED(拒绝)的结果。 |