req icon indicating copy to clipboard operation
req copied to clipboard

进行HTTP摘要认证出错,没有qop参数的时候会报错

Open DarkiT opened this issue 2 years ago • 10 comments

例如使用HTTP摘要认证登陆华为设备会提示:digest: qop must be specified 华为设备返回的摘要信息如下: WWW-Authenticate: Digest realm="Huawei",nonce="66f38e5ec6ebedc7c65c16f1c0ea3f46", algorithm=SHA-256

DarkiT avatar Aug 17 '23 15:08 DarkiT

看起来设备没遵循RFC规范,qop是WWW-Authenticate响应中必带的参数:

qop

This parameter MUST be used by all implementations. It is a quoted string of one or more tokens indicating the "quality of protection" values supported by the server. The value "auth" indicates authentication; the value "auth-int" indicates authentication with integrity protection. See the descriptions below for calculating the response parameter value for the application of this choice. Unrecognized options MUST be ignored.

参考:https://httpwg.org/specs/rfc7616.html#authorization.request.header.field

imroc avatar Aug 18 '23 01:08 imroc

我在想,为了提升使用的便利性,req也不必遵循规范,当响应中没有 qop 参数时,默认指定为 auth

imroc avatar Aug 18 '23 01:08 imroc

已经release了个小版本,你可以升级试下

imroc avatar Aug 18 '23 02:08 imroc

试了下,不行,我提交了一个Pull请求来处理了这个问题,您看看 更新

DarkiT avatar Aug 18 '23 04:08 DarkiT

@DarkiT 最新版做了微调,没用正则,试试看

imroc avatar Aug 21 '23 06:08 imroc

@imroc 获取摘要参数没问题,validateQop() 和 resp() 方法需要修改下,不然计算出来的摘要信息过不了验证。


func (c *credentials) validateQop() error {
	if c.messageQop == "" {
		return nil
	}
	possibleQops := strings.Split(c.messageQop, ", ")
	var authSupport bool
	for _, qop := range possibleQops {
		if qop == "auth" {
			authSupport = true
			break
		}
	}
	if !authSupport {
		return errDigestQopNotSupported
	}

	return nil
}

func (c *credentials) resp() (string, error) {
	c.nc++

	b := make([]byte, 16)
	_, err := io.ReadFull(rand.Reader, b)
	if err != nil {
		return "", err
	}
	c.cNonce = fmt.Sprintf("%x", b)[:32]

	ha1 := c.ha1()
	ha2 := c.ha2()

	if len(c.messageQop) == 0 {
		return c.h(fmt.Sprintf("%s:%s:%s", ha1, c.nonce, ha2)), nil
	}
	return c.kd(ha1, fmt.Sprintf("%s:%08x:%s:%s:%s",
		c.nonce, c.nc, c.cNonce, c.messageQop, ha2)), nil
}

DarkiT avatar Aug 21 '23 11:08 DarkiT

@DarkiT 默认qop已经赋值auth了,相当于默认按auth方式计算摘要,怎么会过不了验证呢

imroc avatar Aug 22 '23 02:08 imroc

主要是这种不标准的摘要在摄像头及流媒体认证里面使用的很广 ,跟常见的网站摘要认证有区别,比如海康、华为的摄像头北向接口基本上都是这种摘要认证,是没有qop参数的,都是这样的: WWW-Authenticate: Digest realm="Huawei",nonce="66f38e5ec6ebedc7c65c16f1c0ea3f46", algorithm=SHA-256 他们计算摘要的方式略有有点区别,只传入了 HA1、NONCE、HA2进行计算。 c.h(fmt.Sprintf("%s:%s:%s", ha1, c.nonce, ha2))

所以我们要在validateQop()方法这里判断messageQop为空也是允许的,不能给他指定auth,然后在resp()方法里面根据messageQop来判断使用哪种方式计算摘要信息。

DarkiT avatar Aug 22 '23 12:08 DarkiT

明白了

imroc avatar Aug 23 '23 03:08 imroc

@DarkiT 又 release了小版本,试试

imroc avatar Aug 23 '23 03:08 imroc