"Injection" is the process of inserting content into the payload of a transport stream somewhere along its network path other than the origin. To prevent injection, you simply need to verify the contents of the payload are the same as they were at the origin. There are many ways to do this.
One method is a checksum. Simply provide a checksum of the payload in the header of the message. The browser would verify the checksum before rendering the page. However, if you can modify the payload, you could also modify this header.
The next method is to use a cryptographic signature. By signing the checksum, you can use a public key to verify the checksum was created by the origin. However, if the first transfer of the public key is not secure, an attacker can replace it with their own public key, making it impossible to tell if this is the origin's content.
One way to solve this is with PKI. If a client maintains a list of trusted certificate authorities, it can verify signed messages in a way that an attacker cannot circumvent by injection. Now we can verify not only that the payload has not changed, but also who signed it (which key, or certificate).
Note that this does not require a secure transport tunnel. Your payload is in the clear, and thus can be easily cached and proxied by any intermediary, but they can not change your data. So why don't we do this?
Simple: the people who have the most influence over these technologies do not want plaintext data on the network, even if its authenticity and integrity are assured. They value privacy over all else, to the point of detriment to users and organizations who would otherwise benefit from such capability.
However, it's not that hard to avoid replay after cache expires. HTTP sends the Date of the response along with Cache-Control instructions. If the headers are also signed they can also be verified by a client. If the client sees that the response has clearly expired, it can discard the document. As a more dirty hack it can also retry it with a new unique query string, or provide it as an HTTP header and token which must be returned in the response.
By the way, — signing is not equal to "null encryption". Signing can be done in advance, once. Signed data can be served via sendfile(). It does not incur CPU overhead on each request. Signing does not require communicating with untrusted parties using vulnerable SSL libraries (which can compromise your entire server).
As we speak, your SSL connection may be tampered with. Someone may be using a heardbleed-like vulnerability in the server or your browser (or both). You won't know about this, because you aren't personally auditing the binary data, that goes in and out of wire… Humorously enough, one needs to actively MITM and record connections to audit them. Plaintext data is easier to audit and reason about.