Roku Developer Program

Developers and content creators—a complete solution for growing an audience directly.
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
slamb
Level 7

External Control API suddenly returns 403 Forbidden

The external control API worked fine for me until a couple days ago. Looks like my Roku 2 got updated to "Software version 8.1.0 * build 4131-04", and since then, I only get 403 Forbidden.

$ curl -v http://roku:8060/keypress/Right
* Hostname was NOT found in DNS cache
*   Trying 192.168.1.56...
* Connected to roku (192.168.1.56) port 8060 (#0)
> GET /keypress/Right HTTP/1.1
> User-Agent: curl/7.38.0
> Host: roku:8060
> Accept: */*
>
< HTTP/1.1 403 Forbidden
* Server Roku UPnP/1.0 MiniUPnPd/1.4 is not blacklisted
< Server: Roku UPnP/1.0 MiniUPnPd/1.4
< Content-Length: 0
<
* Connection #0 to host roku left intact

To be precise, my logs show it worked as of "I0626 22:23:36.452134". Then there was the software update ("Last updated: Jun 27 18:27"), then it didn't work as of the next request ("I0627 20:53:58.250468"). So I'm confident this broke with the update.

I found this article which suggested checking the "Network access" settings. It was set to "Default" which should work (192.168.1.6 to the roku's 192.168.1.56; the network is 192.168.1.0/24) but doesn't. I tried switching to "Permissive". No difference.

I found this thread which suggested using POST instead of GET. Makes sense, but that doesn't help.


$ curl -v http://roku:8060/keypress/Home -d ''
* Hostname was NOT found in DNS cache
*   Trying 192.168.1.56...
* Connected to roku (192.168.1.56) port 8060 (#0)
> POST /keypress/Home HTTP/1.1
> User-Agent: curl/7.38.0
> Host: roku:8060
> Accept: */*
> Content-Length: 0
> Content-Type: application/x-www-form-urlencoded
>
< HTTP/1.1 403 Forbidden
* Server Roku UPnP/1.0 MiniUPnPd/1.4 is not blacklisted
< Server: Roku UPnP/1.0 MiniUPnPd/1.4
< Content-Length: 0
* HTTP error before end of send, stop sending
<
* Closing connection 0

Did anything else change? For example, does it now require https on a different port? I checked the SSDP reply; it still suggests http over port 8060:


16:11:51.257689 IP 192.168.1.56.1900 > 192.168.1.6.36777: UDP, length 215
        0x0000:  4500 00f3 0000 4000 4011 b66b c0a8 0138  E.....@.@..k...8
        0x0010:  c0a8 0106 076c 8fa9 00df 671f 4854 5450  .....l....g.HTTP
        0x0020:  2f31 2e31 2032 3030 204f 4b0d 0a43 6163  /1.1.200.OK..Cac
        0x0030:  6865 2d43 6f6e 7472 6f6c 3a20 6d61 782d  he-Control:.max-
        0x0040:  6167 653d 3336 3030 0d0a 5354 3a20 726f  age=3600..ST:.ro
        0x0050:  6b75 3a65 6370 0d0a 5553 4e3a 2075 7569  ku:ecp..USN:.uui
        0x0060:  643a 726f 6b75 3a65 6370 3a34 4137 3535  d:roku:ecp:4A755
        0x0070:  4e30 3831 3739 380d 0a45 7874 3a20 0d0a  N081798..Ext:...
        0x0080:  5365 7276 6572 3a20 526f 6b75 2055 506e  Server:.Roku.UPn
        0x0090:  502f 312e 3020 526f 6b75 2f38 2e31 2e30  P/1.0.Roku/8.1.0
        0x00a0:  0d0a 4c4f 4341 5449 4f4e 3a20 6874 7470  ..LOCATION:.http
        0x00b0:  3a2f 2f31 3932 2e31 3638 2e31 2e35 363a  ://192.168.1.56:
        0x00c0:  3830 3630 2f0d 0a57 414b 4555 503a 204d  8060/..WAKEUP:.M
        0x00d0:  4143 3d64 303a 3464 3a32 633a 3338 3a62  AC=d0:4d:2c:38:b
        0x00e0:  353a 3834 3b54 696d 656f 7574 3d31 300d  5:84;Timeout=10.
        0x00f0:  0a0d 0a
0 Kudos
9 Replies
Roku Employee
Roku Employee

Re: External Control API suddenly returns 403 Forbidden

"slamb" wrote:
The external control API worked fine for me until a couple days ago. Looks like my Roku 2 got updated to "Software version 8.1.0 * build 4131-04", and since then, I only get 403 Forbidden.

$ curl -v http://roku:8060/keypress/Right


For security reasons, you will need to use the target IP address directly rather than your local DNS alias 'roku'.
0 Kudos
Human
Level 7

Re: External Control API suddenly returns 403 Forbidden

"RokuKC" wrote:
For security reasons, you will need to use the target IP address directly rather than your local DNS alias 'roku'.

Can you explain what attack this protects against? It seems like it's just an inconvenience.
0 Kudos
raptor
Level 7

Re: External Control API suddenly returns 403 Forbidden

The "security" benefit of this change is rather dubious.  It is likely the case that the new Roku FW is looking at the "Host:" header in the HTTP request to confirm that the Roku was addressed on a private network without having to do a DNS query (which can be slow and if you are ultra paranoid not entirely trustworthy).  Additionally if you've simply added an entry to your local "hosts" file a DNS query from the Roku won't return anything (you'd have to be running a DNS server on your LAN, which I do).  If you address the Roku as http://roku/keypress/home then the HTTP Host header will be:  "Host: roku" which isn't obviously originating from the local network, but if you address the Roku as http://192.168.1.1/keypress/home then the Host header is "Host: 192.168.1.1" which can quickly be verified as a private IP subnet (with the presumption that only another device on the subnet could have routed to the same private subnet with a Host header containing the private subnet IP address of the Roku device).

The likely intent here is to prevent people from (ignorantly) port forwarding from the public Internet to their Roku device.  Since ECP implements no authentication (which I think is appropriate given that the privacy issues involved with what the Roku device does are trivial) such port-forwarding would have left the Roku accessible to anyone.  Without a little cleverness, the Host header won't indicate that request originated on a private subnet with a private IP address that matches the one assigned to the Roku and then the Roku can simply refuse the request.  It's an efficient way to make accessing the Roku from the Internet much harder even when the user does something dumb.

I am not sure I understand why this approach was taken over others to ensure both devices in question are on the same private network.  There are more robust ways to accomplish this so maybe I haven't hit on the real reason for the change (the "Host" header can be anything the software making the request wants it to be and guessing the private IP address of the Roku isn't terribly hard given the default router DHCP configurations...).


But at the end of the day this security "improvement" requires that the network already be compromised either by a hacker or a user who doesn't understand the implications of port forwarding.  I am not sure that was worth me spending a couple hours to figure out why home automation quit working with the Rokus and then, once I found this thread, update my interface libraries to do a DNS query so that the HTTP requests could match the new requirement...  
0 Kudos
Willsy7
Level 7

Re: External Control API suddenly returns 403 Forbidden

I'd be interested to hear the why on this too. DNS is good, I don't want to try to remember my hosts by IP address.
0 Kudos
Roku Employee
Roku Employee

Re: External Control API suddenly returns 403 Forbidden

0 Kudos
Human
Level 7

Re: External Control API suddenly returns 403 Forbidden

The same DNS rebinding attack vector is also found on Roku devices (CVE-2018–11314). The researcher says that Roku devices expose an API server on port 8060, accessible from a user's internal network.

An attacker could use a DNS rebinding attack to send requests to this API server and control basic device functions such as launching apps, searching, playing content, and even simulating keys input using a virtual keyboard app.

If my DNS is compromised, it means my router is compromised. If my router is compromised, my network is compromised. I fail to see how it helps to make the Roku require an IP address for API access, since anyone on my compromised network could find its IP address easily.

Regardless, I've already taken care of it on my end in Home Assistant's Roku integration. Hopefully you find a better way to fix it down the road.
0 Kudos
Roku Employee
Roku Employee

Re: External Control API suddenly returns 403 Forbidden

Your DNS can be compromised by an external DNS server advertising a very short time-to-live on an entry.  That will effectively make your local DNS always go to external servers to reacquire the name -> IP mapping, since the local servers have to follow the TTL values they originally received.
0 Kudos
mike_s
Level 8

Re: External Control API suddenly returns 403 Forbidden

"RokuBen" wrote:
https://www.bleepingcomputer.com/news/security/google-roku-sonos-to-fix-dns-rebinding-attack-vector/

You're doing it wrong. 

DNS rebinding attacks work by getting some host (e.g. a user's PC) to access local devices via external names (e.g. badactor.example.com might tell the PC to go to 192.168.1.111, which could be a Roku on the local network). The rebinding attack also doesn't work for hostnames (e.g. simply "roku" instead of "roku.example.com"), only for redirecting accesses to *.badactor.example.com.

So, as long as the HTTP host header is only a hostname and not an FQDN, it should respond. It should also respond to host headers containing FQDNs, as long as the domain matches that of the Roku (whether received via DHCP option or as a static configuration). Oh, the inability to manually configure network settings on a Roku is idiocy. For a device which depends upon network connectivity for it's sole purpose, your developers are woefully uninformed about networking.

Edit: just wanted to add that this change is not documented in the release notes. (at least a simple search for "dns" or "security" doesn't produce relevant results). It should have been.
0 Kudos
doxnal
Level 7

Re: External Control API suddenly returns 403 Forbidden

Definitely annoying, but can be worked around with minimal fuss with some simple command substitution:
curl -vvv http://$(dig +short +search roku)/...

or in Python, easy to do a DNS lookup:
import socket
from roku import Roku
r = Roku(socket.gethostbyname('roku'))

Anyway, glad I found this thread, as I was sometimes input the IP directly and sometimes use the hostname and hadn't yet realized that the intermittent failures were occasions when I had tried to access with the DNS name presenting in the Host header. Thanks all.
0 Kudos