I believe this adds protection against phishing because the browser communicates which origin (that is, which domain name) is sending the challenge, and that gets hashed into the signed response. So if trust-me-im-google.com proxies google.com, it can ask you for a one-time password, and the one-time password will be valid when google.com gets it, so the MITM can get your login cookie. But if you're using U2F, the signed response will say "Yes, I would like to authenticate to trust-me-im-google.com", and google.com will reject that.
[1] describes the flow at a high level, and [2] goes into more details
[1]: https://www.yubico.com/about/background/fido/
[2]: https://developers.yubico.com/U2F/Protocol_details/Overview....
https://developers.yubico.com/U2F/
Yubico has some python code here:
https://github.com/Yubico/python-u2flib-host
https://github.com/Yubico/python-u2flib-server
Chrome builds U2F into the browser itself for website authentication.
Another choice that looks (sadly, for me) more popular: https://github.com/ashtuchkin/u2f