I will ask anyone to jump in here for their own piece of advice.
The way I see it is that a product and a specification have their own life cycles. You can have the product reference specifications by their Id values. In this case the product has no control over the referenced specifications and their invariants, and will allow for the referenced specifications to change freely. On the read side, you can have a model which joins the product with the referenced specifications to represent the product in its entirety with all specifications. Note that the product in the domain does not have full control over its read side representation in this case, because it has no control over the referenced specifications.
The other possibility is to copy the specifications, or some properties of them, to the product. Now the product has full control over its specifications. It can enforce invariants, and will not change if some specification (template) changes. Think of the product as a written document, including all specifications. Do you want the document to read "Product 1: Specifications { [1: Id 71, 2: Id 5, 3: Id 45] }" with possibly changing specifications being referenced by their Id values? Or do you want the document to read "Product 1: Specifications { [ 1: "Details of specification 71", 2: "Details of specification 5", 3: "Details of specification 45"] }. Now the product has full control over the specifications, and it will not change automatically if a specification changes. The "Details of a specification" can include a reference to the "specification", possibly with the used version. It can also only include the properties of the specifications you don't want to reference. You can always update the specifications in a product by some mechanism, for example by manually triggering an update. Of course, if you want all products to always update their specifications if a specification changes, you may as well reference them.
So how you do it depends on the requirements. Also, it is sometimes not easy to move from a relational database view over to a domain driven view. In "the database think", it makes sense to put a reference to specifications on the products, and use the product in different use cases, because it is "the product". In the "domain think" you may determine that a product in one state can reference specifications, and once it is "locked in" it needs to be invariant, and thus will contain the specification details instead of just referencing them. You would probably have two different aggregates for these two product states, because they mean different things.
Hope it helps,
Cheers
Ramin