如何从 WebRTC Flutter 应用程序强制执行 CoTURN 长期凭证验证?

How to force CoTURN long term credentials validation from WebRTC Flutter application?

我在本地网络上使用 this example of Flutter data channel to connect my Android app to my CoTURN server。 CoTURN 日志显示 Android 应用成功连接到 CoTURN 服务器,但未显示任何用户名。我想确保在不使用长期凭据时无法访问我的 CoTURN 服务器。

我的 CoTURN 服务器版本在 Debian Linux 稳定版 (10 Buster) 上是 4.5.1.1-1.1。 lt-cred-mech 已在 CoTURN 服务器配置中设置,而 no-auth 未设置(已注释)。我正在使用 verbose 检查日志。我在我的 MySQL 数据库中创建了一个用户用于长期凭据。在安全端口上使用此命令进行验证:

turnutils_uclient -p 5349 -u myuser -w mypassword 192.168.188.28

它导致 coturn 日志中出现以下内容:

1992: handle_udp_packet: New UDP endpoint: local addr 192.168.188.28:5349, remote addr 192.168.188.28:58256
1992: session 002000000000000002: realm <myrealm> user <>: incoming packet message processed, error 401: Unauthorized
1992: IPv4. Local relay addr: 192.168.188.28:64632
1992: IPv4. Local reserved relay addr: 192.168.188.28:64633
1992: session 002000000000000002: new, realm=<myrealm>, username=<myuser>, lifetime=777
1992: session 002000000000000002: realm <myrealm> user <myuser>: incoming packet ALLOCATE processed, success
1992: session 002000000000000002: refreshed, realm=<myrealm>, username=<myuser>, lifetime=777
1992: session 002000000000000002: realm <myrealm> user <myuser>: incoming packet REFRESH processed, success
...
2007: session 003000000000000003: delete: realm=<myrealm>, username=<myuser>
2007: session 003000000000000003: peer 0.0.0.0:3481 deleted
2008: session 001000000000000008: usage: realm=<myrealm>, username=<myuser>, rp=13, rb=1360, sp=8, sb=768
2008: session 001000000000000008: closed (2nd stage), user <myuser> realm <myrealm> origin <>, local 192.168.188.28:5349, remote 192.168.188.28:48266, reason: allocation timeout
2008: session 001000000000000008: delete: realm=<myrealm>, username=<myuser>
2008: session 001000000000000008: peer 0.0.0.0:3481 deleted

如果我对故意无效的用户尝试相同的命令,我会在服务器日志中得到以下预期结果:

2227: handle_udp_packet: New UDP endpoint: local addr 192.168.188.28:5349, remote addr 192.168.188.28:40431
2227: session 002000000000000003: realm <myrealm> user <>: incoming packet message processed, error 401: Unauthorized
2227: check_stun_auth: Cannot find credentials of user <myuserfaulty>
2227: session 002000000000000003: realm <myrealm> user <myuserfaulty>: incoming packet message processed, error 401: Unauthorized
2227: check_stun_auth: Cannot find credentials of user <myuserfaulty>
...

因此,这意味着 CoTURN 服务器确实检查了凭据。

但是,当我按如下方式向 Flutter 应用程序添加凭据时,我得到的服务器日志似乎没有显示任何用户。最糟糕的是,如果用户故意犯错,它什么也改变不了。这是代码改编的部分:

...
    Map<String, dynamic> configuration = {
      "iceServers": [
        {"url": "stun:192.168.188.28:5349"},
        {"username": "myuserfaulty"},
        {"credential": "mypassword"},
      ]
    };
...

请注意,我从以下文件中猜测配置中的 usernamecredential 条目:

https://github.com/cloudwebrtc/flutter-webrtc/blob/master/ios/Classes/FlutterWebRTCPlugin.m

https://github.com/cloudwebrtc/flutter-webrtc/blob/master/android/src/main/java/com/cloudwebrtc/webrtc/FlutterWebRTCPlugin.java

以下是 CoTURN 日志,同时使用来自 Flutter 的故意错误凭证:

2945: handle_udp_packet: New UDP endpoint: local addr 192.168.188.28:5349, remote addr 192.168.188.31:58350
2945: session 002000000000000004: realm <myrealm> user <>: incoming packet BINDING processed, success
2955: session 002000000000000004: realm <myrealm> user <>: incoming packet BINDING processed, success
2965: session 002000000000000004: realm <myrealm> user <>: incoming packet BINDING processed, success
2975: session 002000000000000004: realm <myrealm> user <>: incoming packet BINDING processed, success
2985: session 002000000000000004: realm <myrealm> user <>: incoming packet BINDING processed, success
2995: session 002000000000000004: realm <myrealm> user <>: incoming packet BINDING processed, success
3005: session 002000000000000004: usage: realm=<myrealm>, username=<>, rp=6, rb=120, sp=6, sb=528
3005: session 002000000000000004: closed (2nd stage), user <> realm <myrealm> origin <>, local 192.168.188.28:5349, remote 192.168.188.31:58350, reason: allocation watchdog determined stale session state
3005: handle_udp_packet: New UDP endpoint: local addr 192.168.188.28:5349, remote addr 192.168.188.31:58350
3005: session 002000000000000005: realm <myrealm> user <>: incoming packet BINDING processed, success
3015: session 002000000000000005: realm <myrealm> user <>: incoming packet BINDING processed, success
...

所以,我有以下问题:

  1. 如何确保在没有授权的长期凭据的情况下无法使用我的 CoTURN 服务器?

  2. 为什么 Flutter 应用程序不受与 turnutils_uclient 相同的凭据验证?

  3. 我是否猜对了在 Flutter 应用程序中通过在配置中添加 usernamecredential 条目来指定凭据的方式?

  1. 使用此配置 (lt-cred-mech),如果没有授权的长期凭据,则无法使用 TURN 服务器。但是,STUN 服务器从不需要身份验证。

  2. turnutils_uclient 命令需要身份验证,因为它调用 TURN 服务器。要进行 STUN 服务器测试调用,可以使用 turnutils_stunclient 命令,但不能向其提供凭据。

  3. Flutter 中 TURN 服务器上的长期身份验证格式在该文件的注释中进行了描述: https://github.com/cloudwebrtc/flutter-webrtc-demo/blob/master/lib/src/call_sample/signaling.dart

...
      {
        'url': 'turn:123.45.67.89:3478',
        'username': 'change_to_real_user',
        'credential': 'change_to_real_secret'
      },
...

这表明我的尝试是错误的,原因有二:

  • 协议必须设置为 turn 而不是 stun。
  • 配置项必须在同一个数组中。

在这些更正之后,我确实在 coturn 服务器日志中得到了用户名,如下所示:

87055: session 000000000000000540: new, realm=<myrealm>, username=<myuser>, lifetime=600
87055: session 000000000000000540: realm <myrealm> user <myuser>: incoming packet ALLOCATE processed, success
87065: session 000000000000000540: realm <myrealm> user <myuser>: incoming packet BINDING processed, success

请注意,coturn 服务器配置也可能需要对 STUN 绑定请求进行身份验证:

...
# Require authentication of the STUN Binding request.
# By default, the clients are allowed anonymous access to the STUN Binding functionality.
#
#secure-stun
...