Security 正在断开数据。设置完整性而不使用GeneraledNewTypeDeriving

Security 正在断开数据。设置完整性而不使用GeneraledNewTypeDeriving,security,haskell,type-safety,language-extension,Security,Haskell,Type Safety,Language Extension,下面的代码使用不安全的GeneralizedNewtypeDeriving扩展来中断数据。通过插入具有不同Ord实例的不同元素来设置: {-# LANGUAGE GeneralizedNewtypeDeriving #-} import Data.Set import System.Random class AlaInt i where fromIntSet :: Set Integer -> Set i toIntSet :: Set i -> Set Integer i

下面的代码使用不安全的
GeneralizedNewtypeDeriving
扩展来中断
数据。通过插入具有不同
Ord
实例的不同元素来设置

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import Data.Set
import System.Random

class AlaInt i where
  fromIntSet :: Set Integer -> Set i
  toIntSet :: Set i -> Set Integer
instance AlaInt Integer where
  fromIntSet = id
  toIntSet = id
newtype I = I Integer deriving (Eq, Show, AlaInt)
instance Ord I where compare (I n1) (I n2) = compare n2 n1 -- sic!  

insert' :: Integer -> Set Integer -> Set Integer
insert' n s = toIntSet $ insert (I n) $ fromIntSet s

randomInput = take 5000 $ zip (randomRs (0,9) gen) (randoms gen) where
    gen = mkStdGen 911

createSet = Prelude.foldr f empty where
    f (e,True) = insert e
    f (e,False) = insert' e

main = print $ toAscList $ createSet randomInput
代码打印
[1,3,5,7,8,6,9,6,4,2,0,9]
。请注意,该列表是无序的,并且有两次
9


是否可以使用其他扩展(例如
ConstraintKinds
)执行此字典交换攻击?如果是,是否可以重新设计
Data.Set
以抵御此类攻击?

我认为这是一个重要的问题,因此我将从其他地方重复我的答案:在Haskell 98中,同一类型的同一类可以有多个实例,而无需任何扩展:

$ cat A.hs
module A where
data U = X | Y deriving (Eq, Show)

$ cat B.hs
module B where
import Data.Set
import A
instance Ord U where
    compare X X = EQ
    compare X Y = LT
    compare Y X = GT
    compare Y Y = EQ
ins :: U -> Set U -> Set U
ins = insert

$ cat C.hs
module C where
import Data.Set
import A
instance Ord U where
    compare X X = EQ
    compare X Y = GT
    compare Y X = LT
    compare Y Y = EQ
ins' :: U -> Set U -> Set U
ins' = insert

$ cat D.hs
module D where
import Data.Set
import A
import B
import C
test = ins' X $ ins X $ ins Y $ empty

$ ghci D.hs
Prelude D> test
fromList [X,Y,X]
是的,您可以通过在内部存储字典来防止此类攻击:

data MSet a where MSet :: Ord a => Set a -> MSet a

test=(ins X.ins'X.ins'Y)empty的可能重复
再现了这个问题。不过,我认为在内部存储字典会妨碍您实现有效的并集和交集操作。可能是这样的。只使用提供的其中一本词典和使用外部词典一样糟糕。请稍加更正。这些模块不构成有效的Haskell 98程序,因为它们为Ord U定义了冲突实例。然而,GHC无论如何都接受这些模块,因为GHC不进行全局实例唯一性检查:它只在需要解决约束时进行检查,约束发生在模块B和C中,每个模块中只有一个实例可见。这是一种已知的(且长期存在的)GHC缺陷。(不知道有多少Haskell程序依赖于缺乏全局唯一性检查…)这是真的。然而,我不认为验证全局唯一性的问题通常可以解决——我的意思是,当您启用了一些扩展时,例如
OverlappingInstances
。GHC支持大量的扩展。