Describe the bug
Everytime an external service tries to communicate with Social the messages cannot be processed and result in a SignatureException as stated by a log entry like seen below.
My setup
Nextcloud running in a docker container <-- http --> Apache with proxy setup 443 to 80 and an official subdomain <-- https --> Internet
First approach of a solution
So I debugged a little and found, that the signature comparison done in SignatureService->generateEstimatedSignature() evaluated the header variable 'Host', which was filled with the name and port of my docker container.
Thinking, that this might be wrong, I took a peek at the available request headers at this point of execution. Apache put the "real", external hostname into X-Forwarded-Host, so I tried building the estimated Signature with this variable instead. This worked, although I can't say that I fully understand the implications of my hack. Here is what my method looks like now (added the second if-block in the loop):
private function generateEstimatedSignature(string $headers, IRequest $request): string {
$keys = explode(' ', $headers);
$target = '';
try {
$target = strtolower($request->getMethod()) . " " . $request->getRequestUri();
} catch (Exception $e) {
}
$estimated = "(request-target): " . $target;
foreach ($keys as $key) {
if ($key === '(request-target)') {
continue;
}
if ($key === 'host' && isset($request->getHeader("X-Forwarded-Host")))
{
$estimated .= "\n" . $key . ': ' . $request->getHeader("X-Forwarded-Host");
continue;
}
$estimated .= "\n" . $key . ': ' . $request->getHeader($key);
}
return $estimated;
}
I can't even say, if this is maybe just a configuration problem of my setup, or if it is really a bug. Or my solution might lead to some horrible security issues. Or it works only on my special setup. All I know is that it worked after that change. What do you think?
To Reproduce
Steps to reproduce the behavior:
Expected behavior
The message is being processed, received and displayed.
Server details
Social app version: 0.1.1
Operating system: Gentoo Linux
Web server: Apache 2.4
Database: MySQL
PHP version: 7.2.13
Nextcloud version: 15.0.0.10
Logs
{"reqId":"WqV8OJgUD7drQlXXqBDk","level":2,"time":"2018-12-23T08:30:59+00:00","remoteAddr":"78.46.16.22","user":"--","app":"no app in context","method":"POST","url":"/index.php/apps/social/@riemy/inbox","message":"500 - {\"status\":-1,\"exception\":\"OCA\\\\Social\\\\Exceptions\\\\SignatureException\",\"message\":\"signature cannot be checked\"}","userAgent":"http.rb/3.3.0 (Mastodon/2.6.5; +https://ruhr.social/)","version":"15.0.0.10","id":"5c1f47c37ea4b"}
This edit makes sense as Apache Proxy changes the Host header and backup the old value in $request->getHeader("X-Forwarded-Host").
We could implement it, but should we check also that the value of the X-Forwarded-Host is the host of our nextcloud ?
Wouldn't it be possible/simple to fix the host-header on the origin or duplicate the host-header on origin and proxy in your Apache setup ?
@juliushaertl @nickvergessen @rullzer
Use $request->getInsecureServerHost() instead https://github.com/nextcloud/server/blob/master/lib/private/AppFramework/Http/Request.php#L863
So I started with using the getInsecureServerHost, but I ended up forcing the value of the Host to the address used in the social App.
We assume that cloud.example.com in @[email protected] is the unique Host that is used to sign the Header of incoming request.
I can confirm this error (without doing further debugging to confirm the cause 100% matches OPs cause) with a nginx proxy in front of Nextcloud running in Docker container. Every interaction (direct message, follow, …) from an external Mastodon instance causes SignatureException: signature cannot be checked.
Sadly the interaction does not go through and it is broken.
Log entry
{
"reqId": "kf7BXH2gYU8cedluiqnw",
"level": 2,
"time": "2018-12-29T13:37:50+00:00",
"remoteAddr": "88.99.89.29",
"user": "--",
"app": "no app in context",
"method": "POST",
"url": "/apps/social/@knut/inbox",
"message": "500 - {\"status\":-1,\"exception\":\"OCA\\\\Social\\\\Exceptions\\\\SignatureException\",\"message\":\"signature cannot be checked\"}",
"userAgent": "http.rb/3.3.0 (Mastodon/2.6.5; +https://chaos.social/)",
"version": "15.0.0.10",
"id": "5c2778aec3946"
}
Would you try this ?
Fixed by #279
Most helpful comment
Would you try this ?
https://github.com/nextcloud/social/pull/279